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, 2012 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>
8 * Copyright (c) 2012 Josh Rickmar <jrick@devio.us>
10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies.
14 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
20 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
26 * xombrero "protocol" (xtp)
27 * We use this for managing stuff like downloads and favorites. They
28 * make magical HTML pages in memory which have xxxt:// links in order
29 * to communicate with xombrero's internals. These links take the format:
30 * xxxt://class/session_key/action/arg
32 * Don't begin xtp class/actions as 0. atoi returns that on error.
34 * Typically we have not put addition of items in this framework, as
35 * adding items is either done via an ex-command or via a keybinding instead.
38 #define XT_HTML_TAG "<html xmlns='http://www.w3.org/1999/xhtml'>\n"
39 #define XT_DOCTYPE "<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'>\n"
40 #define XT_PAGE_STYLE "<style type='text/css'>\n" \
41 "td{overflow: hidden;" \
42 " padding: 2px 2px 2px 2px;" \
43 " border: 1px solid black;" \
44 " vertical-align:top;" \
45 " word-wrap: break-word}\n" \
46 "tr:hover{background: #ffff99}\n" \
47 "th{background-color: #cccccc;" \
48 " border: 1px solid black}\n" \
49 "table{width: 100%%;" \
50 " border: 1px black solid;" \
51 " border-collapse:collapse}\n" \
53 "border: 1px solid black;" \
56 ".progress-inner{float: left;" \
58 " background: green}\n" \
59 ".dlstatus{font-size: small;" \
60 " text-align: center}\n" \
61 "table#settings{background-color: #eee;"\
64 "table#settings td{border: 0px;}\n" \
65 "table#settings th{border: 0px;}\n" \
66 "table#settings tr{" \
67 " background: #f6f6f6;}\n" \
68 "table#settings tr:nth-child(even){" \
69 " background: #eeeeee;}\n" \
70 "table#settings tr#modified{" \
71 " background: #FFFFBA;}\n" \
72 "table#settings tr#modified:nth-child(even){" \
73 " background: #ffffA0;}\n" \
76 int js_show_wl(struct tab
*, struct karg
*);
77 int pl_show_wl(struct tab
*, struct karg
*);
78 int https_show_wl(struct tab
*, struct karg
*);
79 int xtp_page_set(struct tab
*, struct karg
*);
80 int xtp_page_rt(struct tab
*, struct karg
*);
81 int marco(struct tab
*, struct karg
*);
82 int startpage(struct tab
*, struct karg
*);
83 const char * marco_message(int *);
84 void update_cookie_tabs(struct tab
*apart_from
);
85 int about_webkit(struct tab
*, struct karg
*);
86 int allthethings(struct tab
*, struct karg
*);
88 struct about_type about_list
[] = {
89 { XT_URI_ABOUT_ABOUT
, xtp_page_ab
},
90 { XT_URI_ABOUT_ALLTHETHINGS
, allthethings
},
91 { XT_URI_ABOUT_BLANK
, blank
},
92 { XT_URI_ABOUT_CERTS
, ca_cmd
},
93 { XT_URI_ABOUT_COOKIEWL
, cookie_show_wl
},
94 { XT_URI_ABOUT_COOKIEJAR
, xtp_page_cl
},
95 { XT_URI_ABOUT_DOWNLOADS
, xtp_page_dl
},
96 { XT_URI_ABOUT_FAVORITES
, xtp_page_fl
},
97 { XT_URI_ABOUT_HELP
, help
},
98 { XT_URI_ABOUT_HISTORY
, xtp_page_hl
},
99 { XT_URI_ABOUT_JSWL
, js_show_wl
},
100 { XT_URI_ABOUT_SET
, xtp_page_set
},
101 { XT_URI_ABOUT_STATS
, stats
},
102 { XT_URI_ABOUT_MARCO
, marco
},
103 { XT_URI_ABOUT_STARTPAGE
, startpage
},
104 { XT_URI_ABOUT_PLUGINWL
, pl_show_wl
},
105 { XT_URI_ABOUT_HTTPS
, https_show_wl
},
106 { XT_URI_ABOUT_WEBKIT
, about_webkit
},
107 { XT_URI_ABOUT_SEARCH
, xtp_page_sl
},
108 { XT_URI_ABOUT_RUNTIME
, xtp_page_rt
},
109 { XT_URI_ABOUT_SECVIOLATION
, NULL
},
116 { "Google (SSL)", "https://encrypted.google.com/search?q=%s&&client=xombrero" },
117 { "Bing", "http://www.bing.com/search?q=%s" },
118 { "Yahoo", "http://search.yahoo.com/search?p=%s" },
119 { "DuckDuckGo", "https://duckduckgo.com/?q=%s" },
120 { "DuckDuckGo (HTML)", "https://duckduckgo.com/html?q=%s" },
121 { "DuckDuckGo (Lite)", "https://duckduckgo.com/lite?q=%s" },
122 { "Ixquick", "https://ixquick.com/do/search?q=%s" },
123 { "Startpage", "https://startpage.com/do/search?q=%s" },
128 * We use these to prevent people putting xxxt:// URLs on
129 * websites in the wild. We generate 8 bytes and represent in hex (16 chars)
131 #define XT_XTP_SES_KEY_SZ 8
132 #define XT_XTP_SES_KEY_HEX_FMT \
133 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8
135 char *dl_session_key
; /* downloads */
136 char *hl_session_key
; /* history list */
137 char *cl_session_key
; /* cookie list */
138 char *fl_session_key
; /* favorites list */
139 char *sl_session_key
; /* search */
140 char *ab_session_key
; /* about */
141 char *sv_session_key
; /* secviolation */
142 char *rt_session_key
; /* set */
144 int updating_ab_tabs
= 0;
145 int updating_fl_tabs
= 0;
146 int updating_dl_tabs
= 0;
147 int updating_hl_tabs
= 0;
148 int updating_cl_tabs
= 0;
149 int updating_sl_tabs
= 0;
150 int updating_sv_tabs
= 0;
151 int updating_set_tabs
= 0;
152 struct download_list downloads
;
155 about_list_size(void)
157 return (LENGTH(about_list
));
161 get_html_page(gchar
*title
, gchar
*body
, gchar
*head
, bool addstyles
)
165 r
= g_strdup_printf(XT_DOCTYPE XT_HTML_TAG
167 "<title>%s</title>\n"
176 addstyles
? XT_PAGE_STYLE
: "",
185 * Display a web page from a HTML string in memory, rather than from a URL
188 load_webkit_string(struct tab
*t
, const char *str
, gchar
*title
)
193 /* we set this to indicate we want to manually do navaction */
195 t
->item
= webkit_web_back_forward_list_get_current_item(t
->bfl
);
197 t
->xtp_meaning
= XT_XTP_TAB_MEANING_NORMAL
;
199 /* set t->xtp_meaning */
200 for (i
= 0; i
< LENGTH(about_list
); i
++)
201 if (!strcmp(title
, about_list
[i
].name
)) {
206 webkit_web_view_load_string(t
->wv
, str
, NULL
, encoding
,
208 #if GTK_CHECK_VERSION(2, 20, 0)
209 gtk_spinner_stop(GTK_SPINNER(t
->spinner
));
210 gtk_widget_hide(t
->spinner
);
212 snprintf(file
, sizeof file
, "%s" PS
"%s", resource_dir
, icons
[0]);
213 xt_icon_from_file(t
, file
);
218 blank(struct tab
*t
, struct karg
*args
)
221 show_oops(NULL
, "blank invalid parameters");
223 load_webkit_string(t
, "", XT_URI_ABOUT_BLANK
);
229 help(struct tab
*t
, struct karg
*args
)
231 char *page
, *head
, *body
;
234 show_oops(NULL
, "help invalid parameters");
236 head
= "<meta http-equiv=\"REFRESH\" content=\"0;"
237 "url=http://opensource.conformal.com/cgi-bin/man-cgi?xombrero\">"
239 body
= "xombrero man page <a href=\"http://opensource.conformal.com/"
240 "cgi-bin/man-cgi?xombrero\">http://opensource.conformal.com/"
241 "cgi-bin/man-cgi?xombrero</a>";
243 page
= get_html_page(XT_NAME
, body
, head
, FALSE
);
245 load_webkit_string(t
, page
, XT_URI_ABOUT_HELP
);
252 stats(struct tab
*t
, struct karg
*args
)
254 char *page
, *body
, *s
, line
[64 * 1024];
255 uint64_t line_count
= 0;
259 show_oops(NULL
, "stats invalid parameters");
262 if (save_rejected_cookies
) {
263 if ((r_cookie_f
= fopen(rc_fname
, "r"))) {
265 s
= fgets(line
, sizeof line
, r_cookie_f
);
266 if (s
== NULL
|| feof(r_cookie_f
) ||
272 snprintf(line
, sizeof line
,
273 "<br/>Cookies blocked(*) total: %" PRIu64
,
276 show_oops(t
, "Can't open blocked cookies file: %s",
280 body
= g_strdup_printf(
281 "Cookies blocked(*) this session: %" PRIu64
283 "<p><small><b>*</b> results vary based on settings</small></p>",
287 page
= get_html_page("Statistics", body
, "", 0);
290 load_webkit_string(t
, page
, XT_URI_ABOUT_STATS
);
297 show_certs(struct tab
*t
, gnutls_x509_crt_t
*certs
,
298 size_t cert_count
, char *title
)
300 gnutls_datum_t cinfo
;
306 for (i
= 0; i
< cert_count
; i
++) {
307 if (gnutls_x509_crt_print(certs
[i
], GNUTLS_CRT_PRINT_FULL
,
312 body
= g_strdup_printf("%s<h2>Cert #%d</h2><pre>%s</pre>",
313 body
, i
, cinfo
.data
);
314 gnutls_free(cinfo
.data
);
318 tmp
= get_html_page(title
, body
, "", 0);
321 load_webkit_string(t
, tmp
, XT_URI_ABOUT_CERTS
);
326 ca_cmd(struct tab
*t
, struct karg
*args
)
329 int rv
= 1, certs
= 0, certs_read
;
332 gnutls_x509_crt_t
*c
= NULL
;
333 char *certs_buf
= NULL
, *s
;
335 if ((f
= fopen(ssl_ca_file
, "r")) == NULL
) {
336 show_oops(t
, "Can't open CA file: %s", ssl_ca_file
);
340 if (fstat(fileno(f
), &sb
) == -1) {
341 show_oops(t
, "Can't stat CA file: %s", ssl_ca_file
);
345 certs_buf
= g_malloc(sb
.st_size
+ 1);
346 if (fread(certs_buf
, 1, sb
.st_size
, f
) != sb
.st_size
) {
347 show_oops(t
, "Can't read CA file: %s", strerror(errno
));
350 certs_buf
[sb
.st_size
] = '\0';
353 while ((s
= strstr(s
, "BEGIN CERTIFICATE"))) {
355 s
+= strlen("BEGIN CERTIFICATE");
358 bzero(&dt
, sizeof dt
);
359 dt
.data
= (unsigned char *)certs_buf
;
360 dt
.size
= sb
.st_size
;
361 c
= g_malloc(sizeof(gnutls_x509_crt_t
) * certs
);
362 certs_read
= gnutls_x509_crt_list_import(c
, (unsigned int *)&certs
, &dt
,
363 GNUTLS_X509_FMT_PEM
, 0);
364 if (certs_read
<= 0) {
365 show_oops(t
, "No cert(s) available");
368 show_certs(t
, c
, certs_read
, "Certificate Authority Certificates");
381 cookie_show_wl(struct tab
*t
, struct karg
*args
)
383 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
384 wl_show(t
, args
, "Cookie White List", &c_wl
);
390 js_show_wl(struct tab
*t
, struct karg
*args
)
392 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
393 wl_show(t
, args
, "JavaScript White List", &js_wl
);
399 cookie_cmd(struct tab
*t
, struct karg
*args
)
401 if (args
->i
& XT_SHOW
)
402 wl_show(t
, args
, "Cookie White List", &c_wl
);
403 else if (args
->i
& XT_WL_TOGGLE
) {
404 args
->i
|= XT_WL_RELOAD
;
406 } else if (args
->i
& XT_SAVE
) {
407 args
->i
|= XT_WL_RELOAD
;
408 wl_save(t
, args
, XT_WL_COOKIE
);
409 } else if (args
->i
& XT_DELETE
) {
411 update_cookie_tabs(NULL
);
418 js_cmd(struct tab
*t
, struct karg
*args
)
420 if (args
->i
& XT_SHOW
)
421 wl_show(t
, args
, "JavaScript White List", &js_wl
);
422 else if (args
->i
& XT_SAVE
) {
423 args
->i
|= XT_WL_RELOAD
;
424 wl_save(t
, args
, XT_WL_JAVASCRIPT
);
425 } else if (args
->i
& XT_WL_TOGGLE
) {
426 args
->i
|= XT_WL_RELOAD
;
428 } else if (args
->i
& XT_DELETE
)
429 show_oops(t
, "'js delete' currently unimplemented");
435 pl_show_wl(struct tab
*t
, struct karg
*args
)
437 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
438 wl_show(t
, args
, "Plugin White List", &pl_wl
);
444 pl_cmd(struct tab
*t
, struct karg
*args
)
446 if (args
->i
& XT_SHOW
)
447 wl_show(t
, args
, "Plugin White List", &pl_wl
);
448 else if (args
->i
& XT_SAVE
) {
449 args
->i
|= XT_WL_RELOAD
;
450 wl_save(t
, args
, XT_WL_PLUGIN
);
451 } else if (args
->i
& XT_WL_TOGGLE
) {
452 args
->i
|= XT_WL_RELOAD
;
454 } else if (args
->i
& XT_DELETE
)
455 show_oops(t
, "'plugin delete' currently unimplemented");
461 https_show_wl(struct tab
*t
, struct karg
*args
)
463 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
464 wl_show(t
, args
, "HTTPS Force List", &force_https
);
470 https_cmd(struct tab
*t
, struct karg
*args
)
472 if (args
->i
& XT_SHOW
)
473 wl_show(t
, args
, "HTTPS Force List", &force_https
);
474 else if (args
->i
& XT_SAVE
) {
475 args
->i
|= XT_WL_RELOAD
;
476 wl_save(t
, args
, XT_WL_HTTPS
);
477 } else if (args
->i
& XT_WL_TOGGLE
) {
478 args
->i
|= XT_WL_RELOAD
;
479 toggle_force_https(t
, args
);
480 } else if (args
->i
& XT_DELETE
)
481 show_oops(t
, "https delete' currently unimplemented");
487 * cancel, remove, etc. downloads
490 xtp_handle_dl(struct tab
*t
, uint8_t cmd
, int id
, const char *query
)
492 struct download find
, *d
= NULL
;
495 const char *uri
= NULL
;
498 DNPRINTF(XT_D_DOWNLOAD
, "download control: cmd %d, id %d\n", cmd
, id
);
500 /* some commands require a valid download id */
501 if (cmd
!= XT_XTP_DL_LIST
) {
502 /* lookup download in question */
504 d
= RB_FIND(download_list
, &downloads
, &find
);
507 show_oops(t
, "%s: no such download", __func__
);
512 /* decide what to do */
514 case XT_XTP_DL_START
:
515 /* our downloads always needs to be
516 * restarted if called from here
518 download_start(t
, d
, XT_DL_RESTART
);
520 case XT_XTP_DL_CANCEL
:
521 webkit_download_cancel(d
->download
);
522 g_object_unref(d
->download
);
523 RB_REMOVE(download_list
, &downloads
, d
);
525 case XT_XTP_DL_UNLINK
:
527 /* XXX uri's aren't handled properly on windows? */
528 unlink(webkit_download_get_destination_uri(d
->download
));
530 uri
= webkit_download_get_destination_uri(d
->download
);
531 if ((file
= g_filename_from_uri(uri
, NULL
, NULL
)) != NULL
) {
537 case XT_XTP_DL_REMOVE
:
538 webkit_download_cancel(d
->download
); /* just incase */
539 g_object_unref(d
->download
);
540 RB_REMOVE(download_list
, &downloads
, d
);
546 show_oops(t
, "%s: unknown command", __func__
);
549 xtp_page_dl(t
, NULL
);
553 xtp_handle_hl(struct tab
*t
, uint8_t cmd
, int id
, const char *query
)
555 struct history
*h
, *next
, *ht
;
559 case XT_XTP_HL_REMOVE
:
560 /* walk backwards, as listed in reverse */
561 for (h
= RB_MAX(history_list
, &hl
); h
!= NULL
; h
= next
) {
562 next
= RB_PREV(history_list
, &hl
, h
);
564 RB_REMOVE(history_list
, &hl
, h
);
565 g_free((gpointer
) h
->title
);
566 g_free((gpointer
) h
->uri
);
573 case XT_XTP_HL_REMOVE_ALL
:
574 RB_FOREACH_SAFE(h
, history_list
, &hl
, ht
)
575 RB_REMOVE(history_list
, &hl
, h
);
578 /* Nothing - just xtp_page_hl() below */
581 show_oops(t
, "%s: unknown command", __func__
);
585 xtp_page_hl(t
, NULL
);
588 /* remove a favorite */
590 remove_favorite(struct tab
*t
, int index
)
592 char file
[PATH_MAX
], *title
, *uri
= NULL
;
593 char *new_favs
, *tmp
;
599 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_FAVS_FILE
);
601 if ((f
= fopen(file
, "r")) == NULL
) {
602 show_oops(t
, "%s: can't open favorites: %s",
603 __func__
, strerror(errno
));
607 /* build a string which will become the new favroites file */
608 new_favs
= g_strdup("");
611 if ((title
= fparseln(f
, &len
, &lineno
, NULL
, 0)) == NULL
)
612 if (feof(f
) || ferror(f
))
614 /* XXX THIS IS NOT THE RIGHT HEURISTIC */
621 if ((uri
= fparseln(f
, &len
, &lineno
, NULL
, 0)) == NULL
) {
622 if (feof(f
) || ferror(f
)) {
623 show_oops(t
, "%s: can't parse favorites %s",
624 __func__
, strerror(errno
));
629 /* as long as this isn't the one we are deleting add to file */
632 new_favs
= g_strdup_printf("%s%s\n%s\n",
633 new_favs
, title
, uri
);
645 /* write back new favorites file */
646 if ((f
= fopen(file
, "w")) == NULL
) {
647 show_oops(t
, "%s: can't open favorites: %s",
648 __func__
, strerror(errno
));
652 if (fwrite(new_favs
, strlen(new_favs
), 1, f
) != 1)
653 show_oops(t
, "%s: can't fwrite", __func__
);
666 add_favorite(struct tab
*t
, struct karg
*args
)
671 size_t urilen
, linelen
;
672 const gchar
*uri
, *title
;
677 /* don't allow adding of xtp pages to favorites */
678 if (t
->xtp_meaning
!= XT_XTP_TAB_MEANING_NORMAL
) {
679 show_oops(t
, "%s: can't add xtp pages to favorites", __func__
);
683 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_FAVS_FILE
);
684 if ((f
= fopen(file
, "r+")) == NULL
) {
685 show_oops(t
, "Can't open favorites file: %s", strerror(errno
));
689 title
= get_title(t
, FALSE
);
692 if (title
== NULL
|| uri
== NULL
) {
693 show_oops(t
, "can't add page to favorites");
697 urilen
= strlen(uri
);
700 if ((line
= fparseln(f
, &linelen
, NULL
, NULL
, 0)) == NULL
)
701 if (feof(f
) || ferror(f
))
704 if (linelen
== urilen
&& !strcmp(line
, uri
))
711 fprintf(f
, "\n%s\n%s", title
, uri
);
717 update_favorite_tabs(NULL
);
723 search_engine_add(char *body
, const char *name
, const char *url
, int select
)
727 body
= g_strdup_printf("%s<tr>"
730 "<td style='text-align: center'>"
731 "<a href='%s%d/%s/%d/%d'>[ Select ]</a></td>"
736 XT_XTP_STR
, XT_XTP_SL
, sl_session_key
, XT_XTP_SL_SET
, select
);
742 xtp_handle_ab(struct tab
*t
, uint8_t cmd
, int arg
, const char *query
)
744 char config
[PATH_MAX
];
749 case XT_XTP_AB_EDIT_CONF
:
750 if (external_editor
== NULL
|| strlen(external_editor
) == 0) {
751 show_oops(t
, "external_editor is unset");
755 snprintf(config
, sizeof config
, "%s" PS
".%s", pwd
->pw_dir
,
757 sv
= g_strsplit(external_editor
, "<file>", -1);
758 cmdstr
= g_strjoinv(config
, sv
);
760 sv
= g_strsplit_set(cmdstr
, " \t", -1);
762 if (!g_spawn_async(NULL
, sv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
,
764 show_oops(t
, "%s: could not spawn process", __func__
);
770 show_oops(t
, "%s, invalid about command", __func__
);
773 xtp_page_ab(t
, NULL
);
776 xtp_handle_fl(struct tab
*t
, uint8_t cmd
, int arg
, const char *query
)
780 /* nothing, just the below call to xtp_page_fl() */
782 case XT_XTP_FL_REMOVE
:
783 remove_favorite(t
, arg
);
786 show_oops(t
, "%s: invalid favorites command", __func__
);
790 xtp_page_fl(t
, NULL
);
794 xtp_handle_cl(struct tab
*t
, uint8_t cmd
, int arg
, const char *query
)
798 /* nothing, just xtp_page_cl() */
800 case XT_XTP_CL_REMOVE
:
803 case XT_XTP_CL_REMOVE_DOMAIN
:
804 remove_cookie_domain(arg
);
806 case XT_XTP_CL_REMOVE_ALL
:
810 show_oops(t
, "%s: unknown cookie xtp command", __func__
);
814 xtp_page_cl(t
, NULL
);
818 xtp_handle_sl(struct tab
*t
, uint8_t cmd
, int arg
, const char *query
)
821 char *enc_search
, *uri
;
826 set_search_string((char *)search_list
[arg
].url
);
827 if (save_runtime_setting("search_string", search_list
[arg
].url
))
828 show_oops(t
, "could not set search_string in runtime");
831 show_oops(t
, "%s: unknown search xtp command", __func__
);
835 search
= gtk_entry_get_text(GTK_ENTRY(t
->search_entry
)); /* static */
836 enc_search
= soup_uri_encode(search
, XT_RESERVED_CHARS
);
837 sv
= g_strsplit(search_string
, "%s", 2);
838 uri
= g_strjoinv(enc_search
, sv
);
846 xtp_handle_sv(struct tab
*t
, uint8_t cmd
, int id
, const char *query
)
848 SoupURI
*soupuri
= NULL
;
849 struct karg args
= {0};
850 struct secviolation find
, *sv
;
851 struct sv_ignore
*svi
= NULL
;
854 if ((sv
= RB_FIND(secviolation_list
, &svl
, &find
)) == NULL
)
857 args
.ptr
= (void *)sv
->t
;
861 case XT_XTP_SV_SHOW_CERT
:
865 case XT_XTP_SV_ALLOW_SESSION
:
866 soupuri
= soup_uri_new(sv
->uri
);
867 svi
= malloc(sizeof(struct sv_ignore
));
868 svi
->domain
= g_strdup(soupuri
->host
);
869 RB_INSERT(sv_ignore_list
, &svil
, svi
);
870 load_uri(t
, sv
->uri
);
873 case XT_XTP_SV_CACHE
:
876 load_uri(t
, sv
->uri
);
880 show_oops(t
, "%s: invalid secviolation command", __func__
);
886 soup_uri_free(soupuri
);
887 RB_REMOVE(secviolation_list
, &svl
, sv
);
891 xtp_handle_rt(struct tab
*t
, uint8_t cmd
, int id
, const char *query
)
893 struct set_reject
*sr
;
894 GHashTable
*new_settings
= NULL
;
896 char *val
, *curval
, *s
;
903 new_settings
= soup_form_decode(query
);
904 for (i
= 0; i
< get_settings_size(); ++i
) {
907 sr
= g_malloc(sizeof *sr
);
908 val
= (char *)g_hash_table_lookup(new_settings
,
911 switch (rs
[i
].type
) {
912 case XT_S_INT
: /* FALLTHROUGH */
914 if (atoi(val
) != *rs
[i
].ival
)
918 if (atof(val
) != *rs
[i
].fval
)
922 s
= (rs
[i
].sval
== NULL
|| *rs
[i
].sval
== NULL
)
924 if (rs
[i
].sval
&& g_strcmp0(val
, s
))
926 else if (rs
[i
].s
&& rs
[i
].s
->get
) {
927 curval
= rs
[i
].s
->get(NULL
);
928 if (g_strcmp0(val
, curval
))
933 case XT_S_INVALID
: /* FALLTHROUGH */
937 if (rs
[i
].activate(val
)) {
938 sr
->name
= g_strdup(rs
[i
].name
);
939 sr
->value
= g_strdup(val
);
940 TAILQ_INSERT_TAIL(&srl
, sr
, entry
);
944 if (save_runtime_setting(rs
[i
].name
, val
))
945 show_oops(t
, "error");
949 show_oops(t
, "%s: invalid set command", __func__
);
954 g_hash_table_destroy(new_settings
);
956 xtp_page_rt(t
, NULL
);
959 /* link an XTP class to it's session key and handler function */
960 struct xtp_despatch
{
963 void (*handle_func
)(struct tab
*, uint8_t, int,
967 struct xtp_despatch xtp_despatches
[] = {
968 { XT_XTP_DL
, &dl_session_key
, xtp_handle_dl
},
969 { XT_XTP_HL
, &hl_session_key
, xtp_handle_hl
},
970 { XT_XTP_FL
, &fl_session_key
, xtp_handle_fl
},
971 { XT_XTP_CL
, &cl_session_key
, xtp_handle_cl
},
972 { XT_XTP_SL
, &sl_session_key
, xtp_handle_sl
},
973 { XT_XTP_AB
, &ab_session_key
, xtp_handle_ab
},
974 { XT_XTP_SV
, &sv_session_key
, xtp_handle_sv
},
975 { XT_XTP_RT
, &rt_session_key
, xtp_handle_rt
},
976 { XT_XTP_INVALID
, NULL
, NULL
}
980 * generate a session key to secure xtp commands.
981 * pass in a ptr to the key in question and it will
982 * be modified in place.
985 generate_xtp_session_key(char **key
)
987 uint8_t rand_bytes
[XT_XTP_SES_KEY_SZ
];
994 arc4random_buf(rand_bytes
, XT_XTP_SES_KEY_SZ
);
995 *key
= g_strdup_printf(XT_XTP_SES_KEY_HEX_FMT
,
996 rand_bytes
[0], rand_bytes
[1], rand_bytes
[2], rand_bytes
[3],
997 rand_bytes
[4], rand_bytes
[5], rand_bytes
[6], rand_bytes
[7]);
999 DNPRINTF(XT_D_DOWNLOAD
, "%s: new session key '%s'\n", __func__
, *key
);
1003 xtp_generate_keys(void)
1005 /* generate session keys for xtp pages */
1006 generate_xtp_session_key(&dl_session_key
);
1007 generate_xtp_session_key(&hl_session_key
);
1008 generate_xtp_session_key(&cl_session_key
);
1009 generate_xtp_session_key(&fl_session_key
);
1010 generate_xtp_session_key(&ab_session_key
);
1011 generate_xtp_session_key(&sv_session_key
);
1015 * validate a xtp session key.
1019 validate_xtp_session_key(struct tab
*t
, char *trusted
, char *untrusted
)
1021 if (strcmp(trusted
, untrusted
) != 0) {
1022 show_oops(t
, "%s: xtp session key mismatch possible spoof",
1031 * is the url xtp protocol? (xxxt://)
1032 * if so, parse and despatch correct bahvior
1035 parse_xtp_url(struct tab
*t
, const char *uri_str
)
1037 SoupURI
*uri
= NULL
;
1038 struct xtp_despatch
*dsp
, *dsp_match
= NULL
;
1045 * sv[0] = session key
1047 * sv[2] = optional argument
1050 DNPRINTF(XT_D_URL
, "%s: url %s\n", __func__
, url
);
1052 if ((uri
= soup_uri_new(uri_str
)) == NULL
)
1054 if (strncmp(uri
->scheme
, XT_XTP_SCHEME
, strlen(XT_XTP_SCHEME
)))
1056 if (uri
->host
== NULL
|| strlen(uri
->host
) == 0)
1059 class = atoi(uri
->host
);
1060 if ((sv
= g_strsplit(uri
->path
+ 1, "/", 3)) == NULL
)
1063 if (sv
[0] == NULL
|| sv
[1] == NULL
)
1066 dsp
= xtp_despatches
;
1067 class = atoi(uri
->host
);
1068 while (dsp
->xtp_class
) {
1069 if (dsp
->xtp_class
== class) {
1076 /* did we find one atall? */
1077 if (dsp_match
== NULL
) {
1078 show_oops(t
, "%s: no matching xtp despatch found", __func__
);
1082 /* check session key and call despatch function */
1083 if (validate_xtp_session_key(t
, *(dsp_match
->session_key
), sv
[0])) {
1084 ret
= TRUE
; /* all is well, this was a valid xtp request */
1086 dsp_match
->handle_func(t
, atoi(sv
[1]), atoi(sv
[2]),
1089 dsp_match
->handle_func(t
, atoi(sv
[1]), 0, uri
->query
);
1102 * update all favorite tabs apart from one. Pass NULL if
1103 * you want to update all.
1106 update_favorite_tabs(struct tab
*apart_from
)
1109 if (!updating_fl_tabs
) {
1110 updating_fl_tabs
= 1; /* stop infinite recursion */
1111 TAILQ_FOREACH(t
, &tabs
, entry
)
1112 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_FL
)
1113 && (t
!= apart_from
))
1114 xtp_page_fl(t
, NULL
);
1115 updating_fl_tabs
= 0;
1120 * update all download tabs apart from one. Pass NULL if
1121 * you want to update all.
1124 update_download_tabs(struct tab
*apart_from
)
1127 if (!updating_dl_tabs
) {
1128 updating_dl_tabs
= 1; /* stop infinite recursion */
1129 TAILQ_FOREACH(t
, &tabs
, entry
)
1130 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_DL
)
1131 && (t
!= apart_from
))
1132 xtp_page_dl(t
, NULL
);
1133 updating_dl_tabs
= 0;
1138 * update all cookie tabs apart from one. Pass NULL if
1139 * you want to update all.
1142 update_cookie_tabs(struct tab
*apart_from
)
1145 if (!updating_cl_tabs
) {
1146 updating_cl_tabs
= 1; /* stop infinite recursion */
1147 TAILQ_FOREACH(t
, &tabs
, entry
)
1148 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_CL
)
1149 && (t
!= apart_from
))
1150 xtp_page_cl(t
, NULL
);
1151 updating_cl_tabs
= 0;
1156 * update all history tabs apart from one. Pass NULL if
1157 * you want to update all.
1160 update_history_tabs(struct tab
*apart_from
)
1164 if (!updating_hl_tabs
) {
1165 updating_hl_tabs
= 1; /* stop infinite recursion */
1166 TAILQ_FOREACH(t
, &tabs
, entry
)
1167 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_HL
)
1168 && (t
!= apart_from
))
1169 xtp_page_hl(t
, NULL
);
1170 updating_hl_tabs
= 0;
1175 * update all search tabs apart from one. Pass NULL if
1176 * you want to update all.
1179 update_search_tabs(struct tab
*apart_from
)
1183 if (!updating_sl_tabs
) {
1184 updating_sl_tabs
= 1; /* stop infinite recursion */
1185 TAILQ_FOREACH(t
, &tabs
, entry
)
1186 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_SL
)
1187 && (t
!= apart_from
))
1188 xtp_page_sl(t
, NULL
);
1189 updating_sl_tabs
= 0;
1194 * update all about tabs apart from one. Pass NULL if
1195 * you want to update all.
1198 update_about_tabs(struct tab
*apart_from
)
1202 if (!updating_ab_tabs
) {
1203 updating_ab_tabs
= 1; /* stop infinite recursion */
1204 TAILQ_FOREACH(t
, &tabs
, entry
)
1205 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_AB
)
1206 && (t
!= apart_from
))
1207 xtp_page_ab(t
, NULL
);
1208 updating_ab_tabs
= 0;
1213 * update all secviolation tabs apart from one. Pass NULL if
1214 * you want to update all.
1217 update_secviolation_tabs(struct tab
*apart_from
)
1221 if (!updating_sv_tabs
) {
1222 updating_sv_tabs
= 1; /* stop infinite recursion */
1223 TAILQ_FOREACH(t
, &tabs
, entry
)
1224 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_SV
)
1225 && (t
!= apart_from
))
1226 xtp_page_sv(t
, NULL
);
1227 updating_sv_tabs
= 0;
1232 xtp_page_ab(struct tab
*t
, struct karg
*args
)
1237 show_oops(NULL
, "about invalid parameters");
1240 * Generate a new session key for next page instance.
1241 * This only happens for the top level call to xtp_page_ab()
1242 * in which case updating_sl_tabs is 0.
1244 if (!updating_ab_tabs
)
1245 generate_xtp_session_key(&ab_session_key
);
1247 body
= g_strdup_printf("<b>Version: %s</b>"
1248 #ifdef XOMBRERO_BUILDSTR
1249 "<br><b>Build: %s</b>"
1251 "<br><b>WebKit: %d.%d.%d</b>"
1252 "<br><b>User Agent: %d.%d</b>"
1253 #ifdef WEBKITGTK_API_VERSION
1254 "<br><b>WebKit API: %.1f</b>"
1256 "<br><b>Configuration: %s" PS
"<a href='%s%d/%s/%d'>.%s</a>"
1257 " (remember to restart the browser after any changes)</b>"
1261 "<li>Marco Peereboom <marco@peereboom.us></li>"
1262 "<li>Stevan Andjelkovic <stevan@student.chalmers.se></li>"
1263 "<li>Edd Barrett <vext01@gmail.com></li>"
1264 "<li>Todd T. Fries <todd@fries.net></li>"
1265 "<li>Raphael Graf <r@undefined.ch></li>"
1266 "<li>Michal Mazurek <akfaew@jasminek.net></li>"
1267 "<li>Josh Rickmar <jrick@devio.us></li>"
1269 "Copyrights and licenses can be found on the xombrero "
1270 "<a href=\"http://opensource.conformal.com/wiki/xombrero\">website</a>"
1272 #ifdef XOMBRERO_BUILDSTR
1273 version
, XOMBRERO_BUILDSTR
,
1277 WEBKIT_MAJOR_VERSION
, WEBKIT_MINOR_VERSION
, WEBKIT_MICRO_VERSION
,
1278 WEBKIT_USER_AGENT_MAJOR_VERSION
, WEBKIT_USER_AGENT_MINOR_VERSION
1279 #ifdef WEBKITGTK_API_VERSION
1280 ,WEBKITGTK_API_VERSION
1286 XT_XTP_AB_EDIT_CONF
,
1290 page
= get_html_page("About", body
, "", 0);
1293 load_webkit_string(t
, page
, XT_URI_ABOUT_ABOUT
);
1295 update_about_tabs(t
);
1302 /* show a list of favorites (bookmarks) */
1304 xtp_page_fl(struct tab
*t
, struct karg
*args
)
1306 char file
[PATH_MAX
];
1308 char *uri
= NULL
, *title
= NULL
;
1309 size_t len
, lineno
= 0;
1311 char *body
, *tmp
, *page
= NULL
;
1312 const char delim
[3] = {'\\', '\\', '\0'};
1314 DNPRINTF(XT_D_FAVORITE
, "%s:", __func__
);
1317 warn("%s: bad param", __func__
);
1319 /* new session key */
1320 if (!updating_fl_tabs
)
1321 generate_xtp_session_key(&fl_session_key
);
1323 /* open favorites */
1324 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_FAVS_FILE
);
1325 if ((f
= fopen(file
, "r")) == NULL
) {
1326 show_oops(t
, "Can't open favorites file: %s", strerror(errno
));
1331 body
= g_strdup_printf("<table style='table-layout:fixed'><tr>"
1332 "<th style='width: 40px'>#</th><th>Link</th>"
1333 "<th style='width: 40px'>Rm</th></tr>\n");
1336 if ((title
= fparseln(f
, &len
, &lineno
, delim
, 0)) == NULL
)
1338 if (strlen(title
) == 0) {
1344 if ((uri
= fparseln(f
, &len
, &lineno
, delim
, 0)) == NULL
)
1345 if (feof(f
) || ferror(f
)) {
1346 show_oops(t
, "favorites file corrupt");
1352 body
= g_strdup_printf("%s<tr>"
1354 "<td><a href='%s'>%s</a></td>"
1355 "<td style='text-align: center'>"
1356 "<a href='%s%d/%s/%d/%d'>X</a></td>"
1358 body
, i
, uri
, title
,
1359 XT_XTP_STR
, XT_XTP_FL
, fl_session_key
, XT_XTP_FL_REMOVE
, i
);
1371 /* if none, say so */
1374 body
= g_strdup_printf("%s<tr>"
1375 "<td colspan='3' style='text-align: center'>"
1376 "No favorites - To add one use the 'favadd' command."
1377 "</td></tr>", body
);
1382 body
= g_strdup_printf("%s</table>", body
);
1392 page
= get_html_page("Favorites", body
, "", 1);
1393 load_webkit_string(t
, page
, XT_URI_ABOUT_FAVORITES
);
1397 update_favorite_tabs(t
);
1406 * Return a new string with a download row (in html)
1407 * appended. Old string is freed.
1410 xtp_page_dl_row(struct tab
*t
, char *html
, struct download
*dl
)
1413 WebKitDownloadStatus stat
;
1414 const gchar
*destination
;
1415 char *status_html
= NULL
, *cmd_html
= NULL
, *new_html
;
1417 char cur_sz
[FMT_SCALED_STRSIZE
];
1418 char tot_sz
[FMT_SCALED_STRSIZE
];
1421 DNPRINTF(XT_D_DOWNLOAD
, "%s: dl->id %d\n", __func__
, dl
->id
);
1423 /* All actions wil take this form:
1424 * xxxt://class/seskey
1426 xtp_prefix
= g_strdup_printf("%s%d/%s/",
1427 XT_XTP_STR
, XT_XTP_DL
, dl_session_key
);
1429 stat
= webkit_download_get_status(dl
->download
);
1432 case WEBKIT_DOWNLOAD_STATUS_FINISHED
:
1433 status_html
= g_strdup_printf("Finished");
1434 cmd_html
= g_strdup_printf(
1435 "<a href='%s%d/%d'>Remove</a> / <a href='%s%d/%d'>Unlink</a>",
1436 xtp_prefix
, XT_XTP_DL_REMOVE
, dl
->id
, xtp_prefix
,
1437 XT_XTP_DL_UNLINK
, dl
->id
);
1439 case WEBKIT_DOWNLOAD_STATUS_STARTED
:
1440 /* gather size info */
1441 progress
= 100 * webkit_download_get_progress(dl
->download
);
1444 webkit_download_get_current_size(dl
->download
), cur_sz
);
1446 webkit_download_get_total_size(dl
->download
), tot_sz
);
1448 status_html
= g_strdup_printf(
1449 "<div style='width: 100%%' align='center'>"
1450 "<div class='progress-outer'>"
1451 "<div class='progress-inner' style='width: %.2f%%'>"
1452 "</div></div></div>"
1453 "<div class='dlstatus'>%s of %s (%.2f%%)</div>",
1454 progress
, cur_sz
, tot_sz
, progress
);
1456 cmd_html
= g_strdup_printf("<a href='%s%d/%d'>Cancel</a>",
1457 xtp_prefix
, XT_XTP_DL_CANCEL
, dl
->id
);
1461 case WEBKIT_DOWNLOAD_STATUS_CANCELLED
:
1462 status_html
= g_strdup_printf("Cancelled");
1463 cmd_html
= g_strdup_printf(
1464 "<a href='%s%d/%d'>Restart</a> / <a href='%s%d/%d'>Remove</a> / <a href='%s%d/%d'>Unlink</a>",
1465 xtp_prefix
, XT_XTP_DL_START
, dl
->id
,
1466 xtp_prefix
, XT_XTP_DL_REMOVE
, dl
->id
, xtp_prefix
,
1467 XT_XTP_DL_UNLINK
, dl
->id
);
1469 case WEBKIT_DOWNLOAD_STATUS_ERROR
:
1470 status_html
= g_strdup_printf("Error!");
1471 cmd_html
= g_strdup_printf(
1472 "<a href='%s%d/%d'>Restart</a> / <a href='%s%d/%d'>Remove</a> / <a href='%s%d/%d'>Unlink</a>",
1473 xtp_prefix
, XT_XTP_DL_START
, dl
->id
,
1474 xtp_prefix
, XT_XTP_DL_REMOVE
, dl
->id
, xtp_prefix
,
1475 XT_XTP_DL_UNLINK
, dl
->id
);
1477 case WEBKIT_DOWNLOAD_STATUS_CREATED
:
1478 cmd_html
= g_strdup_printf("<a href='%s%d/%d'>Start</a> / <a href='%s%d/%d'>Cancel</a>",
1479 xtp_prefix
, XT_XTP_DL_START
, dl
->id
, xtp_prefix
,
1480 XT_XTP_DL_CANCEL
, dl
->id
);
1481 status_html
= g_strdup_printf("Created");
1484 show_oops(t
, "%s: unknown download status", __func__
);
1487 destination
= webkit_download_get_destination_uri(dl
->download
);
1488 /* we might not have a destination set yet */
1490 destination
= webkit_download_get_suggested_filename(dl
->download
);
1491 new_html
= g_strdup_printf(
1492 "%s\n<tr><td>%s</td><td>%s</td>"
1493 "<td style='text-align:center'>%s</td></tr>\n",
1494 html
, basename((char *)destination
),
1495 status_html
, cmd_html
);
1499 g_free(status_html
);
1509 /* cookie management XTP page */
1511 xtp_page_cl(struct tab
*t
, struct karg
*args
)
1513 char *body
, *page
, *tmp
;
1514 int i
= 1; /* all ids start 1 */
1516 GSList
*sc
, *pc
, *pc_start
;
1518 char *type
, *table_headers
, *last_domain
;
1520 DNPRINTF(XT_D_CMD
, "%s", __func__
);
1523 show_oops(NULL
, "%s invalid parameters", __func__
);
1527 /* Generate a new session key */
1528 if (!updating_cl_tabs
)
1529 generate_xtp_session_key(&cl_session_key
);
1532 table_headers
= g_strdup_printf("<table><tr>"
1535 "<th style='width:200px'>Value</th>"
1539 "<th>HTTP<br />only</th>"
1540 "<th style='width:40px'>Rm</th></tr>\n");
1542 sc
= soup_cookie_jar_all_cookies(s_cookiejar
);
1543 pc
= soup_cookie_jar_all_cookies(p_cookiejar
);
1546 body
= g_strdup_printf("<div align=\"center\"><a href=\"%s%d/%s/%d\">"
1547 "[ Remove All Cookies From All Domains ]</a></div>\n",
1548 XT_XTP_STR
, XT_XTP_CL
, cl_session_key
, XT_XTP_CL_REMOVE_ALL
);
1550 last_domain
= g_strdup("");
1551 for (; sc
; sc
= sc
->next
) {
1554 if (strcmp(last_domain
, c
->domain
) != 0) {
1557 g_free(last_domain
);
1558 last_domain
= g_strdup(c
->domain
);
1562 body
= g_strdup_printf("%s</table>"
1563 "<h2>%s</h2><div align=\"center\">"
1564 "<a href='%s%d/%s/%d/%d'>"
1565 "[ Remove All From This Domain ]"
1568 XT_XTP_STR
, XT_XTP_CL
, cl_session_key
,
1569 XT_XTP_CL_REMOVE_DOMAIN
, domain_id
,
1574 body
= g_strdup_printf("<h2>%s</h2>"
1575 "<div align=\"center\">"
1576 "<a href='%s%d/%s/%d/%d'>"
1577 "[ Remove All From This Domain ]</a></div>%s\n",
1578 c
->domain
, XT_XTP_STR
, XT_XTP_CL
,
1579 cl_session_key
, XT_XTP_CL_REMOVE_DOMAIN
,
1580 domain_id
, table_headers
);
1585 for (pc
= pc_start
; pc
; pc
= pc
->next
)
1586 if (soup_cookie_equal(pc
->data
, c
)) {
1587 type
= "Session + Persistent";
1592 body
= g_strdup_printf(
1595 "<td style='word-wrap:normal'>%s</td>"
1597 " <textarea rows='4'>%s</textarea>"
1603 "<td style='text-align:center'>"
1604 "<a href='%s%d/%s/%d/%d'>X</a></td></tr>\n",
1611 soup_date_to_string(c
->expires
, SOUP_DATE_COOKIE
) : "",
1626 soup_cookies_free(sc
);
1627 soup_cookies_free(pc
);
1629 /* small message if there are none */
1631 body
= g_strdup_printf("%s\n<tr><td style='text-align:center'"
1632 "colspan='8'>No Cookies</td></tr>\n", table_headers
);
1635 body
= g_strdup_printf("%s</table>", body
);
1638 page
= get_html_page("Cookie Jar", body
, "", TRUE
);
1640 g_free(table_headers
);
1641 g_free(last_domain
);
1643 load_webkit_string(t
, page
, XT_URI_ABOUT_COOKIEJAR
);
1644 update_cookie_tabs(t
);
1652 xtp_page_hl(struct tab
*t
, struct karg
*args
)
1654 char *body
, *page
, *tmp
;
1656 int i
= 1; /* all ids start 1 */
1658 DNPRINTF(XT_D_CMD
, "%s", __func__
);
1661 show_oops(NULL
, "%s invalid parameters", __func__
);
1665 /* Generate a new session key */
1666 if (!updating_hl_tabs
)
1667 generate_xtp_session_key(&hl_session_key
);
1670 body
= g_strdup_printf("<div align=\"center\"><a href=\"%s%d/%s/%d\">"
1671 "[ Remove All ]</a></div>"
1672 "<table style='table-layout:fixed'><tr>"
1673 "<th>URI</th><th>Title</th><th>Last visited</th>"
1674 "<th style='width: 40px'>Rm</th></tr>\n",
1675 XT_XTP_STR
, XT_XTP_HL
, hl_session_key
, XT_XTP_HL_REMOVE_ALL
);
1677 RB_FOREACH_REVERSE(h
, history_list
, &hl
) {
1679 body
= g_strdup_printf(
1681 "<td><a href='%s'>%s</a></td>"
1684 "<td style='text-align: center'>"
1685 "<a href='%s%d/%s/%d/%d'>X</a></td></tr>\n",
1686 body
, h
->uri
, h
->uri
, h
->title
, ctime(&h
->time
),
1687 XT_XTP_STR
, XT_XTP_HL
, hl_session_key
,
1688 XT_XTP_HL_REMOVE
, i
);
1694 /* small message if there are none */
1697 body
= g_strdup_printf("%s\n<tr><td style='text-align:center'"
1698 "colspan='4'>No History</td></tr>\n", body
);
1703 body
= g_strdup_printf("%s</table>", body
);
1706 page
= get_html_page("History", body
, "", TRUE
);
1710 * update all history manager tabs as the xtp session
1711 * key has now changed. No need to update the current tab.
1712 * Already did that above.
1714 update_history_tabs(t
);
1716 load_webkit_string(t
, page
, XT_URI_ABOUT_HISTORY
);
1723 * Generate a web page detailing the status of any downloads
1726 xtp_page_dl(struct tab
*t
, struct karg
*args
)
1728 struct download
*dl
;
1729 char *body
, *page
, *tmp
;
1733 DNPRINTF(XT_D_DOWNLOAD
, "%s", __func__
);
1736 show_oops(NULL
, "%s invalid parameters", __func__
);
1741 * Generate a new session key for next page instance.
1742 * This only happens for the top level call to xtp_page_dl()
1743 * in which case updating_dl_tabs is 0.
1745 if (!updating_dl_tabs
)
1746 generate_xtp_session_key(&dl_session_key
);
1748 /* header - with refresh so as to update */
1749 if (refresh_interval
>= 1)
1750 ref
= g_strdup_printf(
1751 "<meta http-equiv='refresh' content='%u"
1752 ";url=%s%d/%s/%d' />\n",
1761 body
= g_strdup_printf("<div align='center'>"
1762 "<p>\n<a href='%s%d/%s/%d'>\n[ Refresh Downloads ]</a>\n"
1763 "</p><table><tr><th style='width: 60%%'>"
1764 "File</th>\n<th>Progress</th><th>Command</th></tr>\n",
1765 XT_XTP_STR
, XT_XTP_DL
, dl_session_key
, XT_XTP_DL_LIST
);
1767 RB_FOREACH_REVERSE(dl
, download_list
, &downloads
) {
1768 body
= xtp_page_dl_row(t
, body
, dl
);
1772 /* message if no downloads in list */
1775 body
= g_strdup_printf("%s\n<tr><td colspan='3'"
1776 " style='text-align: center'>"
1777 "No downloads</td></tr>\n", body
);
1782 body
= g_strdup_printf("%s</table></div>", body
);
1785 page
= get_html_page("Downloads", body
, ref
, 1);
1790 * update all download manager tabs as the xtp session
1791 * key has now changed. No need to update the current tab.
1792 * Already did that above.
1794 update_download_tabs(t
);
1796 load_webkit_string(t
, page
, XT_URI_ABOUT_DOWNLOADS
);
1803 xtp_page_sl(struct tab
*t
, struct karg
*args
)
1806 char *page
, *body
, *tmp
;
1808 DNPRINTF(XT_D_SEARCH
, "%s", __func__
);
1811 * Generate a new session key for next page instance.
1812 * This only happens for the top level call to xtp_page_sl()
1813 * in which case updating_sl_tabs is 0.
1815 if (!updating_sl_tabs
)
1816 generate_xtp_session_key(&sl_session_key
);
1819 show_oops(NULL
, "%s invalid parameters", __func__
);
1823 body
= g_strdup_printf("<p>The xombrero authors will not choose a "
1824 "default search engine for you. What follows is a list of search "
1825 "engines (in no particular order) you may be interested in. "
1826 "To permanently choose a search engine, click [ Select ] to save "
1827 "<tt>search_string</tt> as a runtime setting, or set "
1828 "<tt>search_string</tt> to the appropriate URL in your xombrero "
1829 "configuration.</p>");
1832 body
= g_strdup_printf("%s\n<table style='table-layout:fixed'><tr>"
1833 "<th style='width: 200px'>Name</th><th>URL</th>"
1834 "<th style='width: 100px'>Select</th></tr>\n", body
);
1837 for (i
= 0; i
< (sizeof search_list
/ sizeof (struct search_type
)); ++i
)
1838 body
= search_engine_add(body
, search_list
[i
].name
,
1839 search_list
[i
].url
, i
);
1842 body
= g_strdup_printf("%s</table>", body
);
1845 page
= get_html_page("Choose a search engine", body
, "", 1);
1849 * update all search tabs as the xtp session key has now changed. No
1850 * need to update the current tab. Already did that above.
1852 update_search_tabs(t
);
1854 load_webkit_string(t
, page
, XT_URI_ABOUT_SEARCH
);
1861 xtp_page_sv(struct tab
*t
, struct karg
*args
)
1865 struct secviolation find
, *sv
;
1869 show_oops(NULL
, "secviolation invalid parameters");
1872 * Generate a new session key for next page instance.
1873 * This only happens for the top level call to xtp_page_ab()
1874 * in which case updating_sv_tabs = 0.
1876 if (!updating_sv_tabs
)
1877 generate_xtp_session_key(&sv_session_key
);
1880 find
.xtp_arg
= t
->xtp_arg
;
1881 sv
= RB_FIND(secviolation_list
, &svl
, &find
);
1885 sv
= g_malloc(sizeof(struct secviolation
));
1886 sv
->xtp_arg
= ++arg
;
1890 RB_INSERT(secviolation_list
, &svl
, sv
);
1893 if (sv
->uri
== NULL
|| (soupuri
= soup_uri_new(sv
->uri
)) == NULL
)
1896 body
= g_strdup_printf(
1897 "The domain of the page you have tried to access, %s, has a "
1898 "different remote certificate then the local cached version from a "
1899 "previous visit. As a security precaution to help prevent against "
1900 "man-in-the-middle attacks, please choose one of the following "
1901 "actions to continue, or disable the <tt>warn_cert_changes</tt> "
1902 "setting in your xombrero configuration."
1903 "<p><b>Choose an action:"
1904 "<br><a href='%s%d/%s/%d/%d'>Show Certificate</a>"
1905 "<br><a href='%s%d/%s/%d/%d'>Allow for this Session</a>"
1906 "<br><a href='%s%d/%s/%d/%d'>Cache new certificate</a>",
1908 XT_XTP_STR
, XT_XTP_SV
, sv_session_key
, XT_XTP_SV_SHOW_CERT
,
1910 XT_XTP_STR
, XT_XTP_SV
, sv_session_key
, XT_XTP_SV_ALLOW_SESSION
,
1912 XT_XTP_STR
, XT_XTP_SV
, sv_session_key
, XT_XTP_SV_CACHE
,
1915 page
= get_html_page("Security Violation", body
, "", 0);
1918 update_secviolation_tabs(t
);
1920 load_webkit_string(t
, page
, XT_URI_ABOUT_SECVIOLATION
);
1924 soup_uri_free(soupuri
);
1930 startpage(struct tab
*t
, struct karg
*args
)
1932 char *page
, *body
, *b
;
1936 show_oops(NULL
, "startpage invalid parameters");
1938 body
= g_strdup_printf("<b>Startup Exception(s):</b><p>");
1940 TAILQ_FOREACH(s
, &spl
, entry
) {
1942 body
= g_strdup_printf("%s%s<br>", body
, s
->line
);
1946 page
= get_html_page("Startup Exception", body
, "", 0);
1949 load_webkit_string(t
, page
, XT_URI_ABOUT_STARTPAGE
);
1956 startpage_add(const char *fmt
, ...)
1966 if ((msg
= g_strdup_vprintf(fmt
, ap
)) == NULL
)
1967 errx(1, "startpage_add failed");
1970 s
= g_malloc0(sizeof *s
);
1973 TAILQ_INSERT_TAIL(&spl
, s
, entry
);
1977 show_g_object_settings(GObject
*o
, char *str
, int recurse
)
1979 char *b
, *body
, *valstr
;
1986 const gchar
*string
;
1995 GParamSpec
**proplist
;
1996 char *tmpstr
, *tmpsettings
;
1998 if (!G_IS_OBJECT(o
)) {
1999 fprintf(stderr
, "%s is not a g_object\n", str
);
2000 return g_strdup("");
2002 proplist
= g_object_class_list_properties(
2003 G_OBJECT_GET_CLASS(o
), &n_props
);
2004 body
= g_strdup_printf("%s: %3d settings\n", str
, n_props
);
2005 for (i
=0; i
< n_props
; i
++) {
2006 pspec
= proplist
[i
];
2007 tname
= G_OBJECT_TYPE_NAME(pspec
);
2008 bzero(&value
, sizeof value
);
2011 if (!(pspec
->flags
& G_PARAM_READABLE
))
2012 valstr
= g_strdup_printf("not a readable property");
2014 g_value_init(&value
, G_PARAM_SPEC_VALUE_TYPE(pspec
));
2015 g_object_get_property(G_OBJECT(o
), pspec
->name
,
2019 /* based on the type, recurse and display values */
2020 if (valstr
== NULL
) {
2021 typeno
= G_TYPE_FUNDAMENTAL( G_VALUE_TYPE(&value
) );
2024 number
= g_value_get_enum(&value
);
2025 valstr
= g_strdup_printf("%d", number
);
2028 number
= g_value_get_int(&value
);
2029 valstr
= g_strdup_printf("%d", number
);
2032 number64
= (int64_t)g_value_get_int64(&value
);
2033 valstr
= g_strdup_printf("%" PRIo64
, number64
);
2036 unumber
= g_value_get_uint(&value
);
2037 valstr
= g_strdup_printf("%d", unumber
);
2041 (uint64_t)g_value_get_uint64(&value
);
2043 g_strdup_printf("%" PRIu64
, unumber64
);
2046 unumber
= g_value_get_flags(&value
);
2047 valstr
= g_strdup_printf("0x%x", unumber
);
2049 case G_TYPE_BOOLEAN
:
2050 boolean
= g_value_get_boolean(&value
);
2051 valstr
= g_strdup_printf("%s",
2052 boolean
? "TRUE" : "FALSE");
2055 fp
= g_value_get_float(&value
);
2056 valstr
= g_strdup_printf("%f", fp
);
2059 fpd
= g_value_get_double(&value
);
2060 valstr
= g_strdup_printf("%f", fpd
);
2063 string
= g_value_get_string(&value
);
2064 valstr
= g_strdup_printf("\"%s\"",
2068 object
= g_value_get_object(&value
);
2069 if (object
!= NULL
) {
2071 tmpstr
= g_strdup_printf("%s ",
2073 tmpsettings
= show_g_object_settings(
2074 object
, tmpstr
, recurse
);
2075 valstr
= g_strdup_printf(
2079 g_free(tmpsettings
);
2081 valstr
= g_strdup_printf("<...>");
2084 valstr
= g_strdup_printf("NULL");
2088 valstr
= g_strdup_printf(
2089 "type %s unhandled",
2095 body
= g_strdup_printf(
2096 "%s%s: %3d: flags=0x%08x, %-13s %s = %s\n",
2097 body
, str
, i
, pspec
->flags
, tname
, pspec
->name
,
2107 about_webkit(struct tab
*t
, struct karg
*arg
)
2109 char *page
, *body
, *settingstr
;
2111 settingstr
= show_g_object_settings(G_OBJECT(t
->settings
),
2113 body
= g_strdup_printf("<pre>%s</pre>\n", settingstr
);
2116 page
= get_html_page("About Webkit", body
, "", 0);
2119 load_webkit_string(t
, page
, XT_URI_ABOUT_WEBKIT
);
2126 allthethings(struct tab
*t
, struct karg
*arg
)
2128 char *page
, *body
, *b
, *settingstr
;
2129 extern GtkWidget
*main_window
;
2131 body
= show_g_object_settings(G_OBJECT(t
->wv
), "t->wv", 1);
2133 settingstr
= show_g_object_settings(G_OBJECT(t
->inspector
),
2135 body
= g_strdup_printf("%s%s", body
, settingstr
);
2139 settingstr
= show_g_object_settings(G_OBJECT(main_window
),
2141 body
= g_strdup_printf("%s%s", body
, settingstr
);
2145 body
= g_strdup_printf("<pre>%scan paste clipboard = %d\n</pre>", body
,
2146 webkit_web_view_can_paste_clipboard(t
->wv
));
2149 page
= get_html_page("About All The Things _o/", body
, "", 0);
2152 load_webkit_string(t
, page
, XT_URI_ABOUT_ALLTHETHINGS
);