/*
* Copyright (c) 2010, 2011 Marco Peereboom
* Copyright (c) 2011 Stevan Andjelkovic
* Copyright (c) 2010, 2011 Edd Barrett
* Copyright (c) 2011 Todd T. Fries
* Copyright (c) 2011 Raphael Graf
* Copyright (c) 2011 Michal Mazurek
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "xxxterm.h"
/*
* xxxterm "protocol" (xtp)
* We use this for managing stuff like downloads and favorites. They
* make magical HTML pages in memory which have xxxt:// links in order
* to communicate with xxxterm's internals. These links take the format:
* xxxt://class/session_key/action/arg
*
* Don't begin xtp class/actions as 0. atoi returns that on error.
*
* Typically we have not put addition of items in this framework, as
* adding items is either done via an ex-command or via a keybinding instead.
*/
#define XT_HTML_TAG "\n"
#define XT_DOCTYPE "\n"
#define XT_PAGE_STYLE "\n"
/* XTP classes (xxxt://) */
#define XT_XTP_INVALID (0) /* invalid */
#define XT_XTP_DL (1) /* downloads */
#define XT_XTP_HL (2) /* history */
#define XT_XTP_CL (3) /* cookies */
#define XT_XTP_FL (4) /* favorites */
/* XTP download actions */
#define XT_XTP_DL_LIST (1)
#define XT_XTP_DL_CANCEL (2)
#define XT_XTP_DL_REMOVE (3)
/* XTP history actions */
#define XT_XTP_HL_LIST (1)
#define XT_XTP_HL_REMOVE (2)
/* XTP cookie actions */
#define XT_XTP_CL_LIST (1)
#define XT_XTP_CL_REMOVE (2)
/* XTP cookie actions */
#define XT_XTP_FL_LIST (1)
#define XT_XTP_FL_REMOVE (2)
int ca_cmd(struct tab *, struct karg *);
int cookie_show_wl(struct tab *, struct karg *);
int js_show_wl(struct tab *, struct karg *);
int pl_show_wl(struct tab *, struct karg *);
int set(struct tab *, struct karg *);
int marco(struct tab *, struct karg *);
int startpage(struct tab *, struct karg *);
const char * marco_message(int *);
struct about_type about_list[] = {
{ XT_URI_ABOUT_ABOUT, about },
{ XT_URI_ABOUT_BLANK, blank },
{ XT_URI_ABOUT_CERTS, ca_cmd },
{ XT_URI_ABOUT_COOKIEWL, cookie_show_wl },
{ XT_URI_ABOUT_COOKIEJAR, xtp_page_cl },
{ XT_URI_ABOUT_DOWNLOADS, xtp_page_dl },
{ XT_URI_ABOUT_FAVORITES, xtp_page_fl },
{ XT_URI_ABOUT_HELP, help },
{ XT_URI_ABOUT_HISTORY, xtp_page_hl },
{ XT_URI_ABOUT_JSWL, js_show_wl },
{ XT_URI_ABOUT_SET, set },
{ XT_URI_ABOUT_STATS, stats },
{ XT_URI_ABOUT_MARCO, marco },
{ XT_URI_ABOUT_STARTPAGE, startpage },
{ XT_URI_ABOUT_PLUGINWL, pl_show_wl },
};
/*
* Session IDs.
* We use these to prevent people putting xxxt:// URLs on
* websites in the wild. We generate 8 bytes and represent in hex (16 chars)
*/
#define XT_XTP_SES_KEY_SZ 8
#define XT_XTP_SES_KEY_HEX_FMT \
"%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
char *dl_session_key; /* downloads */
char *hl_session_key; /* history list */
char *cl_session_key; /* cookie list */
char *fl_session_key; /* favorites list */
int updating_fl_tabs = 0;
int updating_dl_tabs = 0;
int updating_hl_tabs = 0;
int updating_cl_tabs = 0;
struct download_list downloads;
size_t
about_list_size(void)
{
return (LENGTH(about_list));
}
gchar *
get_html_page(gchar *title, gchar *body, gchar *head, bool addstyles)
{
gchar *r;
r = g_strdup_printf(XT_DOCTYPE XT_HTML_TAG
"\n"
"%s\n"
"%s"
"%s"
"\n"
"\n"
"%s
\n"
"%s\n\n"
"",
title,
addstyles ? XT_PAGE_STYLE : "",
head,
title,
body);
return (r);
}
/*
* Display a web page from a HTML string in memory, rather than from a URL
*/
void
load_webkit_string(struct tab *t, const char *str, gchar *title)
{
char file[PATH_MAX];
int i;
/* we set this to indicate we want to manually do navaction */
if (t->bfl)
t->item = webkit_web_back_forward_list_get_current_item(t->bfl);
t->xtp_meaning = XT_XTP_TAB_MEANING_NORMAL;
if (title) {
/* set t->xtp_meaning */
for (i = 0; i < LENGTH(about_list); i++)
if (!strcmp(title, about_list[i].name)) {
t->xtp_meaning = i;
break;
}
webkit_web_view_load_string(t->wv, str, NULL, encoding,
"file://");
#if GTK_CHECK_VERSION(2, 20, 0)
gtk_spinner_stop(GTK_SPINNER(t->spinner));
gtk_widget_hide(t->spinner);
#endif
snprintf(file, sizeof file, "%s/%s", resource_dir, icons[0]);
xt_icon_from_file(t, file);
}
}
int
blank(struct tab *t, struct karg *args)
{
if (t == NULL)
show_oops(NULL, "blank invalid parameters");
load_webkit_string(t, "", XT_URI_ABOUT_BLANK);
return (0);
}
int
about(struct tab *t, struct karg *args)
{
char *page, *body;
if (t == NULL)
show_oops(NULL, "about invalid parameters");
body = g_strdup_printf("Version: %s"
#ifdef XXXTERM_BUILDSTR
"
Build: %s"
#endif
""
"Authors:"
"
"
"- Marco Peereboom <marco@peereboom.us>
"
"- Stevan Andjelkovic <stevan@student.chalmers.se>
"
"- Edd Barrett <vext01@gmail.com>
"
"- Todd T. Fries <todd@fries.net>
"
"- Raphael Graf <r@undefined.ch>
"
"- Michal Mazurek <akfaew@jasminek.net>
- "
"
"
"Copyrights and licenses can be found on the XXXTerm "
"website"
"
",
#ifdef XXXTERM_BUILDSTR
version, XXXTERM_BUILDSTR
#else
version
#endif
);
page = get_html_page("About", body, "", 0);
g_free(body);
load_webkit_string(t, page, XT_URI_ABOUT_ABOUT);
g_free(page);
return (0);
}
int
help(struct tab *t, struct karg *args)
{
char *page, *head, *body;
if (t == NULL)
show_oops(NULL, "help invalid parameters");
head = ""
"\n";
body = "XXXTerm man page http://opensource.conformal.com/"
"cgi-bin/man-cgi?xxxterm";
page = get_html_page(XT_NAME, body, head, FALSE);
load_webkit_string(t, page, XT_URI_ABOUT_HELP);
g_free(page);
return (0);
}
int
stats(struct tab *t, struct karg *args)
{
char *page, *body, *s, line[64 * 1024];
long long unsigned int line_count = 0;
FILE *r_cookie_f;
if (t == NULL)
show_oops(NULL, "stats invalid parameters");
line[0] = '\0';
if (save_rejected_cookies) {
if ((r_cookie_f = fopen(rc_fname, "r"))) {
for (;;) {
s = fgets(line, sizeof line, r_cookie_f);
if (s == NULL || feof(r_cookie_f) ||
ferror(r_cookie_f))
break;
line_count++;
}
fclose(r_cookie_f);
snprintf(line, sizeof line,
"
Cookies blocked(*) total: %llu", line_count);
} else
show_oops(t, "Can't open blocked cookies file: %s",
strerror(errno));
}
body = g_strdup_printf(
"Cookies blocked(*) this session: %llu"
"%s"
"* results vary based on settings
",
blocked_cookies,
line);
page = get_html_page("Statistics", body, "", 0);
g_free(body);
load_webkit_string(t, page, XT_URI_ABOUT_STATS);
g_free(page);
return (0);
}
/*
* cancel, remove, etc. downloads
*/
void
xtp_handle_dl(struct tab *t, uint8_t cmd, int id)
{
struct download find, *d = NULL;
DNPRINTF(XT_D_DOWNLOAD, "download control: cmd %d, id %d\n", cmd, id);
/* some commands require a valid download id */
if (cmd != XT_XTP_DL_LIST) {
/* lookup download in question */
find.id = id;
d = RB_FIND(download_list, &downloads, &find);
if (d == NULL) {
show_oops(t, "%s: no such download", __func__);
return;
}
}
/* decide what to do */
switch (cmd) {
case XT_XTP_DL_CANCEL:
webkit_download_cancel(d->download);
break;
case XT_XTP_DL_REMOVE:
webkit_download_cancel(d->download); /* just incase */
g_object_unref(d->download);
RB_REMOVE(download_list, &downloads, d);
break;
case XT_XTP_DL_LIST:
/* Nothing */
break;
default:
show_oops(t, "%s: unknown command", __func__);
break;
};
xtp_page_dl(t, NULL);
}
/*
* Actions on history, only does one thing for now, but
* we provide the function for future actions
*/
void
xtp_handle_hl(struct tab *t, uint8_t cmd, int id)
{
struct history *h, *next;
int i = 1;
switch (cmd) {
case XT_XTP_HL_REMOVE:
/* walk backwards, as listed in reverse */
for (h = RB_MAX(history_list, &hl); h != NULL; h = next) {
next = RB_PREV(history_list, &hl, h);
if (id == i) {
RB_REMOVE(history_list, &hl, h);
g_free((gpointer) h->title);
g_free((gpointer) h->uri);
g_free(h);
break;
}
i++;
}
break;
case XT_XTP_HL_LIST:
/* Nothing - just xtp_page_hl() below */
break;
default:
show_oops(t, "%s: unknown command", __func__);
break;
};
xtp_page_hl(t, NULL);
}
/* remove a favorite */
void
remove_favorite(struct tab *t, int index)
{
char file[PATH_MAX], *title, *uri = NULL;
char *new_favs, *tmp;
FILE *f;
int i;
size_t len, lineno;
/* open favorites */
snprintf(file, sizeof file, "%s/%s", work_dir, XT_FAVS_FILE);
if ((f = fopen(file, "r")) == NULL) {
show_oops(t, "%s: can't open favorites: %s",
__func__, strerror(errno));
return;
}
/* build a string which will become the new favroites file */
new_favs = g_strdup("");
for (i = 1;;) {
if ((title = fparseln(f, &len, &lineno, NULL, 0)) == NULL)
if (feof(f) || ferror(f))
break;
/* XXX THIS IS NOT THE RIGHT HEURISTIC */
if (len == 0) {
free(title);
title = NULL;
continue;
}
if ((uri = fparseln(f, &len, &lineno, NULL, 0)) == NULL) {
if (feof(f) || ferror(f)) {
show_oops(t, "%s: can't parse favorites %s",
__func__, strerror(errno));
goto clean;
}
}
/* as long as this isn't the one we are deleting add to file */
if (i != index) {
tmp = new_favs;
new_favs = g_strdup_printf("%s%s\n%s\n",
new_favs, title, uri);
g_free(tmp);
}
free(uri);
uri = NULL;
free(title);
title = NULL;
i++;
}
fclose(f);
/* write back new favorites file */
if ((f = fopen(file, "w")) == NULL) {
show_oops(t, "%s: can't open favorites: %s",
__func__, strerror(errno));
goto clean;
}
if (fwrite(new_favs, strlen(new_favs), 1, f) != 1)
show_oops(t, "%s: can't fwrite"); /* shut gcc up */
fclose(f);
clean:
if (uri)
free(uri);
if (title)
free(title);
g_free(new_favs);
}
void
xtp_handle_fl(struct tab *t, uint8_t cmd, int arg)
{
switch (cmd) {
case XT_XTP_FL_LIST:
/* nothing, just the below call to xtp_page_fl() */
break;
case XT_XTP_FL_REMOVE:
remove_favorite(t, arg);
break;
default:
show_oops(t, "%s: invalid favorites command", __func__);
break;
};
xtp_page_fl(t, NULL);
}
void
xtp_handle_cl(struct tab *t, uint8_t cmd, int arg)
{
switch (cmd) {
case XT_XTP_CL_LIST:
/* nothing, just xtp_page_cl() */
break;
case XT_XTP_CL_REMOVE:
remove_cookie(arg);
break;
default:
show_oops(t, "%s: unknown cookie xtp command", __func__);
break;
};
xtp_page_cl(t, NULL);
}
/* link an XTP class to it's session key and handler function */
struct xtp_despatch {
uint8_t xtp_class;
char **session_key;
void (*handle_func)(struct tab *, uint8_t, int);
};
struct xtp_despatch xtp_despatches[] = {
{ XT_XTP_DL, &dl_session_key, xtp_handle_dl },
{ XT_XTP_HL, &hl_session_key, xtp_handle_hl },
{ XT_XTP_FL, &fl_session_key, xtp_handle_fl },
{ XT_XTP_CL, &cl_session_key, xtp_handle_cl },
{ XT_XTP_INVALID, NULL, NULL }
};
/*
* generate a session key to secure xtp commands.
* pass in a ptr to the key in question and it will
* be modified in place.
*/
void
generate_xtp_session_key(char **key)
{
uint8_t rand_bytes[XT_XTP_SES_KEY_SZ];
/* free old key */
if (*key)
g_free(*key);
/* make a new one */
arc4random_buf(rand_bytes, XT_XTP_SES_KEY_SZ);
*key = g_strdup_printf(XT_XTP_SES_KEY_HEX_FMT,
rand_bytes[0], rand_bytes[1], rand_bytes[2], rand_bytes[3],
rand_bytes[4], rand_bytes[5], rand_bytes[6], rand_bytes[7]);
DNPRINTF(XT_D_DOWNLOAD, "%s: new session key '%s'\n", __func__, *key);
}
void
xtp_generate_keys(void)
{
/* generate session keys for xtp pages */
generate_xtp_session_key(&dl_session_key);
generate_xtp_session_key(&hl_session_key);
generate_xtp_session_key(&cl_session_key);
generate_xtp_session_key(&fl_session_key);
}
/*
* validate a xtp session key.
* return (1) if OK
*/
int
validate_xtp_session_key(struct tab *t, char *trusted, char *untrusted)
{
if (strcmp(trusted, untrusted) != 0) {
show_oops(t, "%s: xtp session key mismatch possible spoof",
__func__);
return (0);
}
return (1);
}
/*
* is the url xtp protocol? (xxxt://)
* if so, parse and despatch correct bahvior
*/
int
parse_xtp_url(struct tab *t, const char *url)
{
char *dup = NULL, *p, *last = NULL;
uint8_t n_tokens = 0;
char *tokens[4] = {NULL, NULL, NULL, ""};
struct xtp_despatch *dsp, *dsp_match = NULL;
uint8_t req_class;
int ret = FALSE;
/*
* tokens array meaning:
* tokens[0] = class
* tokens[1] = session key
* tokens[2] = action
* tokens[3] = optional argument
*/
DNPRINTF(XT_D_URL, "%s: url %s\n", __func__, url);
if (strncmp(url, XT_XTP_STR, strlen(XT_XTP_STR)))
goto clean;
dup = g_strdup(url + strlen(XT_XTP_STR));
/* split out the url */
for ((p = strtok_r(dup, "/", &last)); p;
(p = strtok_r(NULL, "/", &last))) {
if (n_tokens < 4)
tokens[n_tokens++] = p;
}
/* should be atleast three fields 'class/seskey/command/arg' */
if (n_tokens < 3)
goto clean;
dsp = xtp_despatches;
req_class = atoi(tokens[0]);
while (dsp->xtp_class) {
if (dsp->xtp_class == req_class) {
dsp_match = dsp;
break;
}
dsp++;
}
/* did we find one atall? */
if (dsp_match == NULL) {
show_oops(t, "%s: no matching xtp despatch found", __func__);
goto clean;
}
/* check session key and call despatch function */
if (validate_xtp_session_key(t, *(dsp_match->session_key), tokens[1])) {
ret = TRUE; /* all is well, this was a valid xtp request */
dsp_match->handle_func(t, atoi(tokens[2]), atoi(tokens[3]));
}
clean:
if (dup)
g_free(dup);
return (ret);
}
/*
* update all favorite tabs apart from one. Pass NULL if
* you want to update all.
*/
void
update_favorite_tabs(struct tab *apart_from)
{
struct tab *t;
if (!updating_fl_tabs) {
updating_fl_tabs = 1; /* stop infinite recursion */
TAILQ_FOREACH(t, &tabs, entry)
if ((t->xtp_meaning == XT_XTP_TAB_MEANING_FL)
&& (t != apart_from))
xtp_page_fl(t, NULL);
updating_fl_tabs = 0;
}
}
/*
* update all download tabs apart from one. Pass NULL if
* you want to update all.
*/
void
update_download_tabs(struct tab *apart_from)
{
struct tab *t;
if (!updating_dl_tabs) {
updating_dl_tabs = 1; /* stop infinite recursion */
TAILQ_FOREACH(t, &tabs, entry)
if ((t->xtp_meaning == XT_XTP_TAB_MEANING_DL)
&& (t != apart_from))
xtp_page_dl(t, NULL);
updating_dl_tabs = 0;
}
}
/*
* update all cookie tabs apart from one. Pass NULL if
* you want to update all.
*/
void
update_cookie_tabs(struct tab *apart_from)
{
struct tab *t;
if (!updating_cl_tabs) {
updating_cl_tabs = 1; /* stop infinite recursion */
TAILQ_FOREACH(t, &tabs, entry)
if ((t->xtp_meaning == XT_XTP_TAB_MEANING_CL)
&& (t != apart_from))
xtp_page_cl(t, NULL);
updating_cl_tabs = 0;
}
}
/*
* update all history tabs apart from one. Pass NULL if
* you want to update all.
*/
void
update_history_tabs(struct tab *apart_from)
{
struct tab *t;
if (!updating_hl_tabs) {
updating_hl_tabs = 1; /* stop infinite recursion */
TAILQ_FOREACH(t, &tabs, entry)
if ((t->xtp_meaning == XT_XTP_TAB_MEANING_HL)
&& (t != apart_from))
xtp_page_hl(t, NULL);
updating_hl_tabs = 0;
}
}
/* show a list of favorites (bookmarks) */
int
xtp_page_fl(struct tab *t, struct karg *args)
{
char file[PATH_MAX];
FILE *f;
char *uri = NULL, *title = NULL;
size_t len, lineno = 0;
int i, failed = 0;
char *body, *tmp, *page = NULL;
const char delim[3] = {'\\', '\\', '\0'};
DNPRINTF(XT_D_FAVORITE, "%s:", __func__);
if (t == NULL)
warn("%s: bad param", __func__);
/* new session key */
if (!updating_fl_tabs)
generate_xtp_session_key(&fl_session_key);
/* open favorites */
snprintf(file, sizeof file, "%s/%s", work_dir, XT_FAVS_FILE);
if ((f = fopen(file, "r")) == NULL) {
show_oops(t, "Can't open favorites file: %s", strerror(errno));
return (1);
}
/* body */
body = g_strdup_printf(""
"# | Link | "
"Rm |
\n");
for (i = 1;;) {
if ((title = fparseln(f, &len, &lineno, delim, 0)) == NULL)
break;
if (strlen(title) == 0 || title[0] == '#') {
free(title);
title = NULL;
continue;
}
if ((uri = fparseln(f, &len, &lineno, delim, 0)) == NULL)
if (feof(f) || ferror(f)) {
show_oops(t, "favorites file corrupt");
failed = 1;
break;
}
tmp = body;
body = g_strdup_printf("%s"
"%d | "
"%s | "
""
"X | "
"
\n",
body, i, uri, title,
XT_XTP_STR, XT_XTP_FL, fl_session_key, XT_XTP_FL_REMOVE, i);
g_free(tmp);
free(uri);
uri = NULL;
free(title);
title = NULL;
i++;
}
fclose(f);
/* if none, say so */
if (i == 1) {
tmp = body;
body = g_strdup_printf("%s"
""
"No favorites - To add one use the 'favadd' command."
" |
", body);
g_free(tmp);
}
tmp = body;
body = g_strdup_printf("%s
", body);
g_free(tmp);
if (uri)
free(uri);
if (title)
free(title);
/* render */
if (!failed) {
page = get_html_page("Favorites", body, "", 1);
load_webkit_string(t, page, XT_URI_ABOUT_FAVORITES);
g_free(page);
}
update_favorite_tabs(t);
if (body)
g_free(body);
return (failed);
}
/*
* Return a new string with a download row (in html)
* appended. Old string is freed.
*/
char *
xtp_page_dl_row(struct tab *t, char *html, struct download *dl)
{
WebKitDownloadStatus stat;
char *status_html = NULL, *cmd_html = NULL, *new_html;
gdouble progress;
char cur_sz[FMT_SCALED_STRSIZE];
char tot_sz[FMT_SCALED_STRSIZE];
char *xtp_prefix;
DNPRINTF(XT_D_DOWNLOAD, "%s: dl->id %d\n", __func__, dl->id);
/* All actions wil take this form:
* xxxt://class/seskey
*/
xtp_prefix = g_strdup_printf("%s%d/%s/",
XT_XTP_STR, XT_XTP_DL, dl_session_key);
stat = webkit_download_get_status(dl->download);
switch (stat) {
case WEBKIT_DOWNLOAD_STATUS_FINISHED:
status_html = g_strdup_printf("Finished");
cmd_html = g_strdup_printf(
"Remove",
xtp_prefix, XT_XTP_DL_REMOVE, dl->id);
break;
case WEBKIT_DOWNLOAD_STATUS_STARTED:
/* gather size info */
progress = 100 * webkit_download_get_progress(dl->download);
fmt_scaled(
webkit_download_get_current_size(dl->download), cur_sz);
fmt_scaled(
webkit_download_get_total_size(dl->download), tot_sz);
status_html = g_strdup_printf(
""
"%s of %s (%.2f%%)
",
progress, cur_sz, tot_sz, progress);
cmd_html = g_strdup_printf("Cancel",
xtp_prefix, XT_XTP_DL_CANCEL, dl->id);
break;
/* LLL */
case WEBKIT_DOWNLOAD_STATUS_CANCELLED:
status_html = g_strdup_printf("Cancelled");
cmd_html = g_strdup_printf("Remove",
xtp_prefix, XT_XTP_DL_REMOVE, dl->id);
break;
case WEBKIT_DOWNLOAD_STATUS_ERROR:
status_html = g_strdup_printf("Error!");
cmd_html = g_strdup_printf("Remove",
xtp_prefix, XT_XTP_DL_REMOVE, dl->id);
break;
case WEBKIT_DOWNLOAD_STATUS_CREATED:
cmd_html = g_strdup_printf("Cancel",
xtp_prefix, XT_XTP_DL_CANCEL, dl->id);
status_html = g_strdup_printf("Starting");
break;
default:
show_oops(t, "%s: unknown download status", __func__);
};
new_html = g_strdup_printf(
"%s\n%s | %s | "
"%s |
\n",
html, basename((char *)webkit_download_get_destination_uri(dl->download)),
status_html, cmd_html);
g_free(html);
if (status_html)
g_free(status_html);
if (cmd_html)
g_free(cmd_html);
g_free(xtp_prefix);
return new_html;
}
/* cookie management XTP page */
int
xtp_page_cl(struct tab *t, struct karg *args)
{
char *body, *page, *tmp;
int i = 1; /* all ids start 1 */
GSList *sc, *pc, *pc_start;
SoupCookie *c;
char *type, *table_headers, *last_domain;
DNPRINTF(XT_D_CMD, "%s", __func__);
if (t == NULL) {
show_oops(NULL, "%s invalid parameters", __func__);
return (1);
}
/* Generate a new session key */
if (!updating_cl_tabs)
generate_xtp_session_key(&cl_session_key);
/* table headers */
table_headers = g_strdup_printf(""
"Type | "
"Name | "
"Value | "
"Path | "
"Expires | "
"Secure | "
"HTTP only | "
"Rm |
\n");
sc = soup_cookie_jar_all_cookies(s_cookiejar);
pc = soup_cookie_jar_all_cookies(p_cookiejar);
pc_start = pc;
body = NULL;
last_domain = strdup("");
for (; sc; sc = sc->next) {
c = sc->data;
if (strcmp(last_domain, c->domain) != 0) {
/* new domain */
free(last_domain);
last_domain = strdup(c->domain);
if (body != NULL) {
tmp = body;
body = g_strdup_printf("%s
"
"%s
%s\n",
body, c->domain, table_headers);
g_free(tmp);
} else {
/* first domain */
body = g_strdup_printf("%s
%s\n",
c->domain, table_headers);
}
}
type = "Session";
for (pc = pc_start; pc; pc = pc->next)
if (soup_cookie_equal(pc->data, c)) {
type = "Session + Persistent";
break;
}
tmp = body;
body = g_strdup_printf(
"%s\n"
"%s | "
"%s | "
""
" "
" | "
"%s | "
"%s | "
"%d | "
"%d | "
""
"X |
\n",
body,
type,
c->name,
c->value,
c->path,
c->expires ?
soup_date_to_string(c->expires, SOUP_DATE_COOKIE) : "",
c->secure,
c->http_only,
XT_XTP_STR,
XT_XTP_CL,
cl_session_key,
XT_XTP_CL_REMOVE,
i
);
g_free(tmp);
i++;
}
soup_cookies_free(sc);
soup_cookies_free(pc);
/* small message if there are none */
if (i == 1) {
body = g_strdup_printf("%s\nNo Cookies |
\n", table_headers);
}
tmp = body;
body = g_strdup_printf("%s", body);
g_free(tmp);
page = get_html_page("Cookie Jar", body, "", TRUE);
g_free(body);
g_free(table_headers);
g_free(last_domain);
load_webkit_string(t, page, XT_URI_ABOUT_COOKIEJAR);
update_cookie_tabs(t);
g_free(page);
return (0);
}
int
xtp_page_hl(struct tab *t, struct karg *args)
{
char *body, *page, *tmp;
struct history *h;
int i = 1; /* all ids start 1 */
DNPRINTF(XT_D_CMD, "%s", __func__);
if (t == NULL) {
show_oops(NULL, "%s invalid parameters", __func__);
return (1);
}
/* Generate a new session key */
if (!updating_hl_tabs)
generate_xtp_session_key(&hl_session_key);
/* body */
body = g_strdup_printf(""
"URI | Title | Rm |
\n");
RB_FOREACH_REVERSE(h, history_list, &hl) {
tmp = body;
body = g_strdup_printf(
"%s\n"
"%s | "
"%s | "
""
"X |
\n",
body, h->uri, h->uri, h->title,
XT_XTP_STR, XT_XTP_HL, hl_session_key,
XT_XTP_HL_REMOVE, i);
g_free(tmp);
i++;
}
/* small message if there are none */
if (i == 1) {
tmp = body;
body = g_strdup_printf("%s\nNo History |
\n", body);
g_free(tmp);
}
tmp = body;
body = g_strdup_printf("%s
", body);
g_free(tmp);
page = get_html_page("History", body, "", TRUE);
g_free(body);
/*
* update all history manager tabs as the xtp session
* key has now changed. No need to update the current tab.
* Already did that above.
*/
update_history_tabs(t);
load_webkit_string(t, page, XT_URI_ABOUT_HISTORY);
g_free(page);
return (0);
}
/*
* Generate a web page detailing the status of any downloads
*/
int
xtp_page_dl(struct tab *t, struct karg *args)
{
struct download *dl;
char *body, *page, *tmp;
char *ref;
int n_dl = 1;
DNPRINTF(XT_D_DOWNLOAD, "%s", __func__);
if (t == NULL) {
show_oops(NULL, "%s invalid parameters", __func__);
return (1);
}
/*
* Generate a new session key for next page instance.
* This only happens for the top level call to xtp_page_dl()
* in which case updating_dl_tabs is 0.
*/
if (!updating_dl_tabs)
generate_xtp_session_key(&dl_session_key);
/* header - with refresh so as to update */
if (refresh_interval >= 1)
ref = g_strdup_printf(
"\n",
refresh_interval,
XT_XTP_STR,
XT_XTP_DL,
dl_session_key,
XT_XTP_DL_LIST);
else
ref = g_strdup("");
body = g_strdup_printf(""
"
\n\n[ Refresh Downloads ]\n"
"
"
"File | \nProgress | Command |
\n",
XT_XTP_STR, XT_XTP_DL, dl_session_key, XT_XTP_DL_LIST);
RB_FOREACH_REVERSE(dl, download_list, &downloads) {
body = xtp_page_dl_row(t, body, dl);
n_dl++;
}
/* message if no downloads in list */
if (n_dl == 1) {
tmp = body;
body = g_strdup_printf("%s\n"
"No downloads |
\n", body);
g_free(tmp);
}
tmp = body;
body = g_strdup_printf("%s
", body);
g_free(tmp);
page = get_html_page("Downloads", body, ref, 1);
g_free(ref);
g_free(body);
/*
* update all download manager tabs as the xtp session
* key has now changed. No need to update the current tab.
* Already did that above.
*/
update_download_tabs(t);
load_webkit_string(t, page, XT_URI_ABOUT_DOWNLOADS);
g_free(page);
return (0);
}