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
*);
89 * If you change the index of any of these, correct the
90 * XT_XTP_TAB_MEANING_* macros in xombrero.h!
92 struct about_type about_list
[] = {
93 { XT_URI_ABOUT_ABOUT
, xtp_page_ab
},
94 { XT_URI_ABOUT_ALLTHETHINGS
, allthethings
},
95 { XT_URI_ABOUT_BLANK
, blank
},
96 { XT_URI_ABOUT_CERTS
, ca_cmd
},
97 { XT_URI_ABOUT_COOKIEWL
, cookie_show_wl
},
98 { XT_URI_ABOUT_COOKIEJAR
, xtp_page_cl
},
99 { XT_URI_ABOUT_DOWNLOADS
, xtp_page_dl
},
100 { XT_URI_ABOUT_FAVORITES
, xtp_page_fl
},
101 { XT_URI_ABOUT_HELP
, help
},
102 { XT_URI_ABOUT_HISTORY
, xtp_page_hl
},
103 { XT_URI_ABOUT_JSWL
, js_show_wl
},
104 { XT_URI_ABOUT_SET
, xtp_page_set
},
105 { XT_URI_ABOUT_STATS
, stats
},
106 { XT_URI_ABOUT_MARCO
, marco
},
107 { XT_URI_ABOUT_STARTPAGE
, startpage
},
108 { XT_URI_ABOUT_PLUGINWL
, pl_show_wl
},
109 { XT_URI_ABOUT_HTTPS
, https_show_wl
},
110 { XT_URI_ABOUT_WEBKIT
, about_webkit
},
111 { XT_URI_ABOUT_SEARCH
, xtp_page_sl
},
112 { XT_URI_ABOUT_RUNTIME
, xtp_page_rt
},
113 { XT_URI_ABOUT_SECVIOLATION
, NULL
},
120 { "Google (SSL)", "https://encrypted.google.com/search?q=%s" },
121 { "Bing", "http://www.bing.com/search?q=%s" },
122 { "Yahoo", "http://search.yahoo.com/search?p=%s" },
123 { "DuckDuckGo", "https://duckduckgo.com/?q=%s" },
124 { "DuckDuckGo (HTML)", "https://duckduckgo.com/html?q=%s" },
125 { "DuckDuckGo (Lite)", "https://duckduckgo.com/lite?q=%s" },
126 { "Ixquick", "https://ixquick.com/do/search?q=%s" },
127 { "Startpage", "https://startpage.com/do/search?q=%s" },
132 * We use these to prevent people putting xxxt:// URLs on
133 * websites in the wild. We generate 8 bytes and represent in hex (16 chars)
135 #define XT_XTP_SES_KEY_SZ 8
136 #define XT_XTP_SES_KEY_HEX_FMT \
137 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8
139 int updating_fl_tabs
= 0;
140 int updating_dl_tabs
= 0;
141 int updating_hl_tabs
= 0;
142 int updating_cl_tabs
= 0;
143 int updating_sl_tabs
= 0;
144 int updating_sv_tabs
= 0;
145 int updating_set_tabs
= 0;
146 struct download_list downloads
;
149 about_list_size(void)
151 return (LENGTH(about_list
));
155 get_html_page(gchar
*title
, gchar
*body
, gchar
*head
, bool addstyles
)
159 r
= g_strdup_printf(XT_DOCTYPE XT_HTML_TAG
161 "<title>%s</title>\n"
170 addstyles
? XT_PAGE_STYLE
: "",
179 * Display a web page from a HTML string in memory, rather than from a URL
182 load_webkit_string(struct tab
*t
, const char *str
, gchar
*title
, int nohist
)
187 if (g_signal_handler_is_connected(t
->wv
, t
->progress_handle
))
188 g_signal_handler_disconnect(t
->wv
, t
->progress_handle
);
190 /* we set this to indicate we want to manually do navaction */
191 if (t
->bfl
&& !nohist
) {
192 t
->item
= webkit_web_back_forward_list_get_current_item(t
->bfl
);
194 g_object_ref(t
->item
);
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
);
216 if (t
->xtp_meaning
== XT_XTP_TAB_MEANING_NORMAL
&&
217 t
->session_key
!= NULL
) {
218 g_free(t
->session_key
);
219 t
->session_key
= NULL
;
222 t
->progress_handle
= g_signal_connect(t
->wv
,
223 "notify::progress", G_CALLBACK(webview_progress_changed_cb
), t
);
227 blank(struct tab
*t
, struct karg
*args
)
230 show_oops(NULL
, "blank invalid parameters");
232 load_webkit_string(t
, "", XT_URI_ABOUT_BLANK
, 0);
238 help(struct tab
*t
, struct karg
*args
)
240 char *page
, *head
, *body
;
243 show_oops(NULL
, "help invalid parameters");
245 head
= "<meta http-equiv=\"REFRESH\" content=\"0;"
246 "url=https://opensource.conformal.com/cgi-bin/man-cgi?xombrero\">"
248 body
= "xombrero man page <a href=\"https://opensource.conformal.com/"
249 "cgi-bin/man-cgi?xombrero\">https://opensource.conformal.com/"
250 "cgi-bin/man-cgi?xombrero</a>";
252 page
= get_html_page(XT_NAME
, body
, head
, FALSE
);
254 load_webkit_string(t
, page
, XT_URI_ABOUT_HELP
, 0);
261 stats(struct tab
*t
, struct karg
*args
)
263 char *page
, *body
, *s
, line
[64 * 1024];
264 uint64_t line_count
= 0;
268 show_oops(NULL
, "stats invalid parameters");
271 if (save_rejected_cookies
) {
272 if ((r_cookie_f
= fopen(rc_fname
, "r"))) {
274 s
= fgets(line
, sizeof line
, r_cookie_f
);
275 if (s
== NULL
|| feof(r_cookie_f
) ||
281 snprintf(line
, sizeof line
,
282 "<br/>Cookies blocked(*) total: %" PRIu64
,
285 show_oops(t
, "Can't open blocked cookies file: %s",
289 body
= g_strdup_printf(
290 "Cookies blocked(*) this session: %" PRIu64
292 "<p><small><b>*</b> results vary based on settings</small></p>",
296 page
= get_html_page("Statistics", body
, "", 0);
299 load_webkit_string(t
, page
, XT_URI_ABOUT_STATS
, 0);
306 show_certs(struct tab
*t
, gnutls_x509_crt_t
*certs
,
307 size_t cert_count
, char *title
)
309 gnutls_datum_t
*cinfo
;
315 for (i
= 0; i
< cert_count
; i
++) {
316 cinfo
= gnutls_malloc(sizeof *cinfo
);
317 if (gnutls_x509_crt_print(certs
[i
], GNUTLS_CRT_PRINT_FULL
,
325 body
= g_strdup_printf("%s<h2>Cert #%d</h2><pre>%s</pre>",
326 body
, i
, cinfo
->data
);
331 tmp
= get_html_page(title
, body
, "", 0);
334 load_webkit_string(t
, tmp
, XT_URI_ABOUT_CERTS
, 0);
339 ca_cmd(struct tab
*t
, struct karg
*args
)
342 int rv
= 1, certs_read
;
343 unsigned int certs
= 0;
346 gnutls_x509_crt_t
*c
= NULL
;
347 char *certs_buf
= NULL
, *s
;
349 if ((f
= fopen(ssl_ca_file
, "r")) == NULL
) {
350 show_oops(t
, "Can't open CA file: %s", ssl_ca_file
);
354 if (fstat(fileno(f
), &sb
) == -1) {
355 show_oops(t
, "Can't stat CA file: %s", ssl_ca_file
);
359 certs_buf
= g_malloc(sb
.st_size
+ 1);
360 if (fread(certs_buf
, 1, sb
.st_size
, f
) != sb
.st_size
) {
361 show_oops(t
, "Can't read CA file: %s", strerror(errno
));
364 certs_buf
[sb
.st_size
] = '\0';
367 while ((s
= strstr(s
, "BEGIN CERTIFICATE"))) {
369 s
+= strlen("BEGIN CERTIFICATE");
372 bzero(&dt
, sizeof dt
);
373 dt
.data
= (unsigned char *)certs_buf
;
374 dt
.size
= sb
.st_size
;
375 c
= gnutls_malloc(sizeof(*c
) * certs
);
376 certs_read
= gnutls_x509_crt_list_import(c
, &certs
, &dt
,
377 GNUTLS_X509_FMT_PEM
, 0);
378 if (certs_read
<= 0) {
379 show_oops(t
, "No cert(s) available");
382 show_certs(t
, c
, certs_read
, "Certificate Authority Certificates");
395 cookie_show_wl(struct tab
*t
, struct karg
*args
)
397 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
398 wl_show(t
, args
, "Cookie White List", &c_wl
);
404 js_show_wl(struct tab
*t
, struct karg
*args
)
406 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
407 wl_show(t
, args
, "JavaScript White List", &js_wl
);
413 cookie_cmd(struct tab
*t
, struct karg
*args
)
415 if (args
->i
& XT_SHOW
)
416 wl_show(t
, args
, "Cookie White List", &c_wl
);
417 else if (args
->i
& XT_WL_TOGGLE
) {
418 args
->i
|= XT_WL_RELOAD
;
420 } else if (args
->i
& XT_SAVE
) {
421 args
->i
|= XT_WL_RELOAD
;
422 wl_save(t
, args
, XT_WL_COOKIE
);
423 } else if (args
->i
& XT_DELETE
) {
425 update_cookie_tabs(NULL
);
432 js_cmd(struct tab
*t
, struct karg
*args
)
434 if (args
->i
& XT_SHOW
)
435 wl_show(t
, args
, "JavaScript White List", &js_wl
);
436 else if (args
->i
& XT_SAVE
) {
437 args
->i
|= XT_WL_RELOAD
;
438 wl_save(t
, args
, XT_WL_JAVASCRIPT
);
439 } else if (args
->i
& XT_WL_TOGGLE
) {
440 args
->i
|= XT_WL_RELOAD
;
442 } else if (args
->i
& XT_DELETE
)
443 show_oops(t
, "'js delete' currently unimplemented");
449 pl_show_wl(struct tab
*t
, struct karg
*args
)
451 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
452 wl_show(t
, args
, "Plugin White List", &pl_wl
);
458 pl_cmd(struct tab
*t
, struct karg
*args
)
460 if (args
->i
& XT_SHOW
)
461 wl_show(t
, args
, "Plugin White List", &pl_wl
);
462 else if (args
->i
& XT_SAVE
) {
463 args
->i
|= XT_WL_RELOAD
;
464 wl_save(t
, args
, XT_WL_PLUGIN
);
465 } else if (args
->i
& XT_WL_TOGGLE
) {
466 args
->i
|= XT_WL_RELOAD
;
468 } else if (args
->i
& XT_DELETE
)
469 show_oops(t
, "'plugin delete' currently unimplemented");
475 https_show_wl(struct tab
*t
, struct karg
*args
)
477 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
478 wl_show(t
, args
, "HTTPS Force List", &force_https
);
484 https_cmd(struct tab
*t
, struct karg
*args
)
486 if (args
->i
& XT_SHOW
)
487 wl_show(t
, args
, "HTTPS Force List", &force_https
);
488 else if (args
->i
& XT_SAVE
) {
489 args
->i
|= XT_WL_RELOAD
;
490 wl_save(t
, args
, XT_WL_HTTPS
);
491 } else if (args
->i
& XT_WL_TOGGLE
) {
492 args
->i
|= XT_WL_RELOAD
;
493 toggle_force_https(t
, args
);
494 } else if (args
->i
& XT_DELETE
)
495 show_oops(t
, "https delete' currently unimplemented");
501 * cancel, remove, etc. downloads
504 xtp_handle_dl(struct tab
*t
, uint8_t cmd
, int id
, const char *query
)
506 struct download find
, *d
= NULL
;
509 const char *uri
= NULL
;
512 DNPRINTF(XT_D_DOWNLOAD
, "download control: cmd %d, id %d\n", cmd
, id
);
514 /* some commands require a valid download id */
515 if (cmd
!= XT_XTP_DL_LIST
) {
516 /* lookup download in question */
518 d
= RB_FIND(download_list
, &downloads
, &find
);
521 show_oops(t
, "%s: no such download", __func__
);
526 /* decide what to do */
528 case XT_XTP_DL_START
:
529 /* our downloads always needs to be
530 * restarted if called from here
532 download_start(t
, d
, XT_DL_RESTART
);
534 case XT_XTP_DL_CANCEL
:
535 webkit_download_cancel(d
->download
);
536 g_object_unref(d
->download
);
537 RB_REMOVE(download_list
, &downloads
, d
);
539 case XT_XTP_DL_UNLINK
:
541 /* XXX uri's aren't handled properly on windows? */
542 unlink(webkit_download_get_destination_uri(d
->download
));
544 uri
= webkit_download_get_destination_uri(d
->download
);
545 if ((file
= g_filename_from_uri(uri
, NULL
, NULL
)) != NULL
) {
551 case XT_XTP_DL_REMOVE
:
552 webkit_download_cancel(d
->download
); /* just incase */
553 g_object_unref(d
->download
);
554 RB_REMOVE(download_list
, &downloads
, d
);
560 show_oops(t
, "%s: unknown command", __func__
);
563 xtp_page_dl(t
, NULL
);
567 xtp_handle_hl(struct tab
*t
, uint8_t cmd
, int id
, const char *query
)
569 struct history
*h
, *next
, *ht
;
573 case XT_XTP_HL_REMOVE
:
574 /* walk backwards, as listed in reverse */
575 for (h
= RB_MAX(history_list
, &hl
); h
!= NULL
; h
= next
) {
576 next
= RB_PREV(history_list
, &hl
, h
);
578 RB_REMOVE(history_list
, &hl
, h
);
579 g_free((gpointer
) h
->title
);
580 g_free((gpointer
) h
->uri
);
587 case XT_XTP_HL_REMOVE_ALL
:
588 RB_FOREACH_SAFE(h
, history_list
, &hl
, ht
)
589 RB_REMOVE(history_list
, &hl
, h
);
592 /* Nothing - just xtp_page_hl() below */
595 show_oops(t
, "%s: unknown command", __func__
);
599 xtp_page_hl(t
, NULL
);
602 /* remove a favorite */
604 remove_favorite(struct tab
*t
, int index
)
606 char file
[PATH_MAX
], *title
, *uri
= NULL
;
607 char *new_favs
, *tmp
;
613 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_FAVS_FILE
);
615 if ((f
= fopen(file
, "r")) == NULL
) {
616 show_oops(t
, "%s: can't open favorites: %s",
617 __func__
, strerror(errno
));
621 /* build a string which will become the new favorites file */
622 new_favs
= g_strdup("");
625 if ((title
= fparseln(f
, &len
, &lineno
, NULL
, 0)) == NULL
)
626 if (feof(f
) || ferror(f
))
628 /* XXX THIS IS NOT THE RIGHT HEURISTIC */
635 if ((uri
= fparseln(f
, &len
, &lineno
, NULL
, 0)) == NULL
) {
636 if (feof(f
) || ferror(f
)) {
637 show_oops(t
, "%s: can't parse favorites %s",
638 __func__
, strerror(errno
));
643 /* as long as this isn't the one we are deleting add to file */
646 new_favs
= g_strdup_printf("%s%s\n%s\n",
647 new_favs
, title
, uri
);
659 /* write back new favorites file */
660 if ((f
= fopen(file
, "w")) == NULL
) {
661 show_oops(t
, "%s: can't open favorites: %s",
662 __func__
, strerror(errno
));
666 if (fwrite(new_favs
, strlen(new_favs
), 1, f
) != 1)
667 show_oops(t
, "%s: can't fwrite", __func__
);
680 add_favorite(struct tab
*t
, struct karg
*args
)
685 size_t urilen
, linelen
;
686 gchar
*argtitle
= NULL
;
687 const gchar
*uri
, *title
;
692 /* don't allow adding of xtp pages to favorites */
693 if (t
->xtp_meaning
!= XT_XTP_TAB_MEANING_NORMAL
) {
694 show_oops(t
, "%s: can't add xtp pages to favorites", __func__
);
698 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_FAVS_FILE
);
699 if ((f
= fopen(file
, "r+")) == NULL
) {
700 show_oops(t
, "Can't open favorites file: %s", strerror(errno
));
704 if (args
->s
&& strlen(g_strstrip(args
->s
)))
705 argtitle
= html_escape(g_strstrip(args
->s
));
707 title
= argtitle
? argtitle
: get_title(t
, FALSE
);
710 if (title
== NULL
|| uri
== NULL
) {
711 show_oops(t
, "can't add page to favorites");
715 urilen
= strlen(uri
);
718 if ((line
= fparseln(f
, &linelen
, NULL
, NULL
, 0)) == NULL
) {
722 show_oops(t
, "Error reading favorites file: %s",
728 if (linelen
== urilen
&& !strcmp(line
, uri
))
735 fprintf(f
, "\n%s\n%s", title
, uri
);
743 update_favorite_tabs(NULL
);
749 search_engine_add(char *body
, const char *name
, const char *url
,
750 const char *key
, int select
)
754 body
= g_strdup_printf("%s<tr>"
757 "<td style='text-align: center'>"
758 "<a href='%s%d/%s/%d/%d'>[ Select ]</a></td>"
763 XT_XTP_STR
, XT_XTP_SL
, key
, XT_XTP_SL_SET
, select
);
769 xtp_handle_ab(struct tab
*t
, uint8_t cmd
, int arg
, const char *query
)
771 char config
[PATH_MAX
];
776 case XT_XTP_AB_EDIT_CONF
:
777 if (external_editor
== NULL
|| strlen(external_editor
) == 0) {
778 show_oops(t
, "external_editor is unset");
782 snprintf(config
, sizeof config
, "%s" PS
".%s", pwd
->pw_dir
,
784 sv
= g_strsplit(external_editor
, "<file>", -1);
785 cmdstr
= g_strjoinv(config
, sv
);
787 sv
= g_strsplit_set(cmdstr
, " \t", -1);
789 if (!g_spawn_async(NULL
, sv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
,
791 show_oops(t
, "%s: could not spawn process", __func__
);
797 show_oops(t
, "%s, invalid about command", __func__
);
800 xtp_page_ab(t
, NULL
);
803 xtp_handle_fl(struct tab
*t
, uint8_t cmd
, int arg
, const char *query
)
805 struct karg args
= {0};
809 /* nothing, just the below call to xtp_page_fl() */
811 case XT_XTP_FL_REMOVE
:
812 remove_favorite(t
, arg
);
816 show_oops(t
, "%s: invalid favorites command", __func__
);
820 xtp_page_fl(t
, &args
);
824 xtp_handle_cl(struct tab
*t
, uint8_t cmd
, int arg
, const char *query
)
828 /* nothing, just xtp_page_cl() */
830 case XT_XTP_CL_REMOVE
:
833 case XT_XTP_CL_REMOVE_DOMAIN
:
834 remove_cookie_domain(arg
);
836 case XT_XTP_CL_REMOVE_ALL
:
840 show_oops(t
, "%s: unknown cookie xtp command", __func__
);
844 xtp_page_cl(t
, NULL
);
848 xtp_handle_sl(struct tab
*t
, uint8_t cmd
, int arg
, const char *query
)
851 char *enc_search
, *uri
;
856 set_search_string((char *)search_list
[arg
].url
);
857 if (save_runtime_setting("search_string", search_list
[arg
].url
))
858 show_oops(t
, "could not set search_string in runtime");
861 show_oops(t
, "%s: unknown search xtp command", __func__
);
865 search
= gtk_entry_get_text(GTK_ENTRY(t
->search_entry
)); /* static */
866 enc_search
= soup_uri_encode(search
, XT_RESERVED_CHARS
);
867 sv
= g_strsplit(search_string
, "%s", 2);
868 uri
= g_strjoinv(enc_search
, sv
);
876 xtp_handle_sv(struct tab
*t
, uint8_t cmd
, int id
, const char *query
)
878 SoupURI
*soupuri
= NULL
;
879 struct karg args
= {0};
880 struct secviolation find
, *sv
;
883 if ((sv
= RB_FIND(secviolation_list
, &svl
, &find
)) == NULL
)
886 args
.ptr
= (void *)sv
->t
;
890 case XT_XTP_SV_SHOW_NEW_CERT
:
892 if (cert_cmd(t
, &args
)) {
893 xtp_page_sv(t
, &args
);
897 case XT_XTP_SV_SHOW_CACHED_CERT
:
898 args
.i
= XT_CACHE
| XT_SHOW
;
899 if (cert_cmd(t
, &args
)) {
900 xtp_page_sv(t
, &args
);
904 case XT_XTP_SV_ALLOW_SESSION
:
905 soupuri
= soup_uri_new(sv
->uri
);
906 wl_add(soupuri
->host
, &svil
, 0);
907 load_uri(t
, sv
->uri
);
910 case XT_XTP_SV_CACHE
:
912 if (cert_cmd(t
, &args
)) {
913 xtp_page_sv(t
, &args
);
916 load_uri(t
, sv
->uri
);
920 show_oops(t
, "%s: invalid secviolation command", __func__
);
926 soup_uri_free(soupuri
);
927 RB_REMOVE(secviolation_list
, &svl
, sv
);
931 xtp_handle_rt(struct tab
*t
, uint8_t cmd
, int id
, const char *query
)
933 struct set_reject
*sr
;
934 GHashTable
*new_settings
= NULL
;
936 char *val
, *curval
, *s
;
943 new_settings
= soup_form_decode(query
);
944 for (i
= 0; i
< get_settings_size(); ++i
) {
947 val
= (char *)g_hash_table_lookup(new_settings
,
950 switch (rs
[i
].type
) {
951 case XT_S_INT
: /* FALLTHROUGH */
953 if (atoi(val
) != *rs
[i
].ival
)
957 if (atof(val
) < (*rs
[i
].fval
- 0.0001) ||
958 atof(val
) > (*rs
[i
].fval
+ 0.0001))
962 s
= (rs
[i
].sval
== NULL
|| *rs
[i
].sval
== NULL
)
964 if (rs
[i
].sval
&& g_strcmp0(val
, s
))
966 else if (rs
[i
].s
&& rs
[i
].s
->get
) {
967 curval
= rs
[i
].s
->get(NULL
);
968 if (g_strcmp0(val
, curval
))
973 case XT_S_INVALID
: /* FALLTHROUGH */
977 if (rs
[i
].activate(val
)) {
978 sr
= g_malloc(sizeof *sr
);
979 sr
->name
= g_strdup(rs
[i
].name
);
980 sr
->value
= g_strdup(val
);
981 TAILQ_INSERT_TAIL(&srl
, sr
, entry
);
985 if (save_runtime_setting(rs
[i
].name
, val
))
986 show_oops(t
, "error");
990 show_oops(t
, "%s: invalid set command", __func__
);
995 g_hash_table_destroy(new_settings
);
997 xtp_page_rt(t
, NULL
);
1000 /* link an XTP class to it's session key and handler function */
1001 struct xtp_despatch
{
1003 void (*handle_func
)(struct tab
*, uint8_t, int,
1007 struct xtp_despatch xtp_despatches
[] = {
1008 { XT_XTP_DL
, xtp_handle_dl
},
1009 { XT_XTP_HL
, xtp_handle_hl
},
1010 { XT_XTP_FL
, xtp_handle_fl
},
1011 { XT_XTP_CL
, xtp_handle_cl
},
1012 { XT_XTP_SL
, xtp_handle_sl
},
1013 { XT_XTP_AB
, xtp_handle_ab
},
1014 { XT_XTP_SV
, xtp_handle_sv
},
1015 { XT_XTP_RT
, xtp_handle_rt
},
1016 { XT_XTP_INVALID
, NULL
}
1020 * generate a session key to secure xtp commands.
1021 * pass in a ptr to the key in question and it will
1022 * be modified in place.
1025 generate_xtp_session_key(char **key
)
1027 uint8_t rand_bytes
[XT_XTP_SES_KEY_SZ
];
1036 /* make a new one */
1037 arc4random_buf(rand_bytes
, XT_XTP_SES_KEY_SZ
);
1038 *key
= g_strdup_printf(XT_XTP_SES_KEY_HEX_FMT
,
1039 rand_bytes
[0], rand_bytes
[1], rand_bytes
[2], rand_bytes
[3],
1040 rand_bytes
[4], rand_bytes
[5], rand_bytes
[6], rand_bytes
[7]);
1042 DNPRINTF(XT_D_DOWNLOAD
, "%s: new session key '%s'\n", __func__
, *key
);
1046 * validate a xtp session key.
1050 validate_xtp_session_key(struct tab
*t
, char *key
)
1052 if (t
== NULL
|| t
->session_key
== NULL
|| key
== NULL
)
1055 if (strcmp(t
->session_key
, key
) != 0) {
1056 show_oops(t
, "%s: xtp session key mismatch possible spoof",
1065 * is the url xtp protocol? (xxxt://)
1066 * if so, parse and despatch correct bahvior
1069 parse_xtp_url(struct tab
*t
, const char *uri_str
)
1071 SoupURI
*uri
= NULL
;
1072 struct xtp_despatch
*dsp
, *dsp_match
= NULL
;
1079 * sv[0] = session key
1081 * sv[2] = optional argument
1084 DNPRINTF(XT_D_URL
, "%s: url %s\n", __func__
, uri_str
);
1086 if ((uri
= soup_uri_new(uri_str
)) == NULL
)
1088 if (strncmp(uri
->scheme
, XT_XTP_SCHEME
, strlen(XT_XTP_SCHEME
)))
1090 if (uri
->host
== NULL
|| strlen(uri
->host
) == 0)
1092 if ((sv
= g_strsplit(uri
->path
+ 1, "/", 3)) == NULL
)
1095 if (sv
[0] == NULL
|| sv
[1] == NULL
)
1098 dsp
= xtp_despatches
;
1099 class = atoi(uri
->host
);
1100 while (dsp
->xtp_class
) {
1101 if (dsp
->xtp_class
== class) {
1108 /* did we find one atall? */
1109 if (dsp_match
== NULL
) {
1110 show_oops(t
, "%s: no matching xtp despatch found", __func__
);
1114 /* check session key and call despatch function */
1115 if (validate_xtp_session_key(t
, sv
[0])) {
1116 ret
= TRUE
; /* all is well, this was a valid xtp request */
1118 dsp_match
->handle_func(t
, atoi(sv
[1]), atoi(sv
[2]),
1121 dsp_match
->handle_func(t
, atoi(sv
[1]), 0, uri
->query
);
1134 * update all favorite tabs apart from one. Pass NULL if
1135 * you want to update all.
1138 update_favorite_tabs(struct tab
*apart_from
)
1142 if (!updating_fl_tabs
) {
1143 updating_fl_tabs
= 1; /* stop infinite recursion */
1144 TAILQ_FOREACH(t
, &tabs
, entry
)
1145 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_FL
)
1146 && (t
!= apart_from
))
1147 xtp_page_fl(t
, NULL
);
1148 updating_fl_tabs
= 0;
1153 * update all download tabs apart from one. Pass NULL if
1154 * you want to update all.
1157 update_download_tabs(struct tab
*apart_from
)
1161 if (!updating_dl_tabs
) {
1162 updating_dl_tabs
= 1; /* stop infinite recursion */
1163 TAILQ_FOREACH(t
, &tabs
, entry
)
1164 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_DL
)
1165 && (t
!= apart_from
))
1166 xtp_page_dl(t
, NULL
);
1167 updating_dl_tabs
= 0;
1172 * update all cookie tabs apart from one. Pass NULL if
1173 * you want to update all.
1176 update_cookie_tabs(struct tab
*apart_from
)
1180 if (!updating_cl_tabs
) {
1181 updating_cl_tabs
= 1; /* stop infinite recursion */
1182 TAILQ_FOREACH(t
, &tabs
, entry
)
1183 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_CL
)
1184 && (t
!= apart_from
))
1185 xtp_page_cl(t
, NULL
);
1186 updating_cl_tabs
= 0;
1191 * update all history tabs apart from one. Pass NULL if
1192 * you want to update all.
1195 update_history_tabs(struct tab
*apart_from
)
1199 if (!updating_hl_tabs
) {
1200 updating_hl_tabs
= 1; /* stop infinite recursion */
1201 TAILQ_FOREACH(t
, &tabs
, entry
)
1202 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_HL
)
1203 && (t
!= apart_from
))
1204 xtp_page_hl(t
, NULL
);
1205 updating_hl_tabs
= 0;
1210 * update all search tabs apart from one. Pass NULL if
1211 * you want to update all.
1214 update_search_tabs(struct tab
*apart_from
)
1218 if (!updating_sl_tabs
) {
1219 updating_sl_tabs
= 1; /* stop infinite recursion */
1220 TAILQ_FOREACH(t
, &tabs
, entry
)
1221 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_SL
)
1222 && (t
!= apart_from
))
1223 xtp_page_sl(t
, NULL
);
1224 updating_sl_tabs
= 0;
1229 xtp_page_ab(struct tab
*t
, struct karg
*args
)
1234 show_oops(NULL
, "about invalid parameters");
1238 generate_xtp_session_key(&t
->session_key
);
1240 body
= g_strdup_printf("<b>Version: %s</b>"
1241 #ifdef XOMBRERO_BUILDSTR
1242 "<br><b>Build: %s</b>"
1244 "<br><b>WebKit: %d.%d.%d</b>"
1245 "<br><b>User Agent: %d.%d</b>"
1246 #ifdef WEBKITGTK_API_VERSION
1247 "<br><b>WebKit API: %.1f</b>"
1249 "<br><b>Configuration: %s" PS
"<a href='%s%d/%s/%d'>.%s</a>"
1250 " (remember to restart the browser after any changes)</b>"
1254 "<li>Marco Peereboom <marco@peereboom.us></li>"
1255 "<li>Stevan Andjelkovic <stevan@student.chalmers.se></li>"
1256 "<li>Edd Barrett <vext01@gmail.com></li>"
1257 "<li>Todd T. Fries <todd@fries.net></li>"
1258 "<li>Raphael Graf <r@undefined.ch></li>"
1259 "<li>Michal Mazurek <akfaew@jasminek.net></li>"
1260 "<li>Josh Rickmar <jrick@devio.us></li>"
1261 "<li>David Hill <dhill@mindcry.org></li>"
1263 "Copyrights and licenses can be found on the xombrero "
1264 "<a href=\"https://opensource.conformal.com/wiki/xombrero\">website</a>"
1266 #ifdef XOMBRERO_BUILDSTR
1267 version
, XOMBRERO_BUILDSTR
,
1271 WEBKIT_MAJOR_VERSION
, WEBKIT_MINOR_VERSION
, WEBKIT_MICRO_VERSION
,
1272 WEBKIT_USER_AGENT_MAJOR_VERSION
, WEBKIT_USER_AGENT_MINOR_VERSION
1273 #ifdef WEBKITGTK_API_VERSION
1274 ,WEBKITGTK_API_VERSION
1279 t
->session_key
? t
->session_key
: "",
1280 XT_XTP_AB_EDIT_CONF
,
1284 page
= get_html_page("About", body
, "", 0);
1287 load_webkit_string(t
, page
, XT_URI_ABOUT_ABOUT
, 0);
1294 /* show a list of favorites (bookmarks) */
1296 xtp_page_fl(struct tab
*t
, struct karg
*args
)
1298 char file
[PATH_MAX
];
1300 char *uri
= NULL
, *title
= NULL
;
1301 size_t len
, lineno
= 0;
1303 char *body
, *tmp
, *page
= NULL
;
1304 const char delim
[3] = {'\\', '\\', '\0'};
1306 DNPRINTF(XT_D_FAVORITE
, "%s:", __func__
);
1309 show_oops(NULL
, "%s: bad param", __func__
);
1313 generate_xtp_session_key(&t
->session_key
);
1315 /* open favorites */
1316 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_FAVS_FILE
);
1317 if ((f
= fopen(file
, "r")) == NULL
) {
1318 show_oops(t
, "Can't open favorites file: %s", strerror(errno
));
1323 if (args
&& args
->i
& XT_DELETE
)
1324 body
= g_strdup_printf("<table style='table-layout:fixed'><tr>"
1325 "<th style='width: 40px'>#</th><th>Link</th>"
1326 "<th style='width: 40px'>Rm</th></tr>\n");
1328 body
= g_strdup_printf("<table style='table-layout:fixed'><tr>"
1329 "<th style='width: 40px'>#</th><th>Link</th></tr>\n");
1332 if ((title
= fparseln(f
, &len
, &lineno
, delim
, 0)) == NULL
)
1334 if (strlen(title
) == 0) {
1340 if ((uri
= fparseln(f
, &len
, &lineno
, delim
, 0)) == NULL
)
1341 if (feof(f
) || ferror(f
)) {
1342 show_oops(t
, "favorites file corrupt");
1348 if (args
&& args
->i
& XT_DELETE
)
1349 body
= g_strdup_printf("%s<tr>"
1351 "<td><a href='%s'>%s</a></td>"
1352 "<td style='text-align: center'>"
1353 "<a href='%s%d/%s/%d/%d'>X</a></td>"
1355 body
, i
, uri
, title
,
1356 XT_XTP_STR
, XT_XTP_FL
,
1357 t
->session_key
? t
->session_key
: "",
1358 XT_XTP_FL_REMOVE
, i
);
1360 body
= g_strdup_printf("%s<tr>"
1362 "<td><a href='%s'>%s</a></td>"
1364 body
, i
, uri
, title
);
1375 /* if none, say so */
1378 body
= g_strdup_printf("%s<tr>"
1379 "<td colspan='%d' style='text-align: center'>"
1380 "No favorites - To add one use the 'favadd' command."
1381 "</td></tr>", body
, (args
&& args
->i
& XT_DELETE
) ? 3 : 2);
1386 body
= g_strdup_printf("%s</table>", body
);
1396 page
= get_html_page("Favorites", body
, "", 1);
1397 load_webkit_string(t
, page
, XT_URI_ABOUT_FAVORITES
, 0);
1401 update_favorite_tabs(t
);
1410 * Return a new string with a download row (in html)
1411 * appended. Old string is freed.
1414 xtp_page_dl_row(struct tab
*t
, char *html
, struct download
*dl
)
1417 WebKitDownloadStatus stat
;
1418 const gchar
*destination
;
1420 char *status_html
= NULL
, *cmd_html
= NULL
, *new_html
;
1422 char cur_sz
[FMT_SCALED_STRSIZE
];
1423 char tot_sz
[FMT_SCALED_STRSIZE
];
1426 DNPRINTF(XT_D_DOWNLOAD
, "%s: dl->id %d\n", __func__
, dl
->id
);
1428 /* All actions wil take this form:
1429 * xxxt://class/seskey
1431 xtp_prefix
= g_strdup_printf("%s%d/%s/",
1432 XT_XTP_STR
, XT_XTP_DL
, t
->session_key
);
1434 stat
= webkit_download_get_status(dl
->download
);
1437 case WEBKIT_DOWNLOAD_STATUS_FINISHED
:
1438 status_html
= g_strdup_printf("Finished");
1439 cmd_html
= g_strdup_printf(
1440 "<a href='%s%d/%d'>Remove</a> / <a href='%s%d/%d'>Unlink</a>",
1441 xtp_prefix
, XT_XTP_DL_REMOVE
, dl
->id
, xtp_prefix
,
1442 XT_XTP_DL_UNLINK
, dl
->id
);
1444 case WEBKIT_DOWNLOAD_STATUS_STARTED
:
1445 /* gather size info */
1446 progress
= 100 * webkit_download_get_progress(dl
->download
);
1449 webkit_download_get_current_size(dl
->download
), cur_sz
);
1451 webkit_download_get_total_size(dl
->download
), tot_sz
);
1453 status_html
= g_strdup_printf(
1454 "<div style='width: 100%%' align='center'>"
1455 "<div class='progress-outer'>"
1456 "<div class='progress-inner' style='width: %.2f%%'>"
1457 "</div></div></div>"
1458 "<div class='dlstatus'>%s of %s (%.2f%%)</div>",
1459 progress
, cur_sz
, tot_sz
, progress
);
1461 cmd_html
= g_strdup_printf("<a href='%s%d/%d'>Cancel</a>",
1462 xtp_prefix
, XT_XTP_DL_CANCEL
, dl
->id
);
1466 case WEBKIT_DOWNLOAD_STATUS_CANCELLED
:
1467 status_html
= g_strdup_printf("Cancelled");
1468 cmd_html
= g_strdup_printf(
1469 "<a href='%s%d/%d'>Restart</a> / <a href='%s%d/%d'>Remove</a> / <a href='%s%d/%d'>Unlink</a>",
1470 xtp_prefix
, XT_XTP_DL_START
, dl
->id
,
1471 xtp_prefix
, XT_XTP_DL_REMOVE
, dl
->id
, xtp_prefix
,
1472 XT_XTP_DL_UNLINK
, dl
->id
);
1474 case WEBKIT_DOWNLOAD_STATUS_ERROR
:
1475 status_html
= g_strdup_printf("Error!");
1476 cmd_html
= g_strdup_printf(
1477 "<a href='%s%d/%d'>Restart</a> / <a href='%s%d/%d'>Remove</a> / <a href='%s%d/%d'>Unlink</a>",
1478 xtp_prefix
, XT_XTP_DL_START
, dl
->id
,
1479 xtp_prefix
, XT_XTP_DL_REMOVE
, dl
->id
, xtp_prefix
,
1480 XT_XTP_DL_UNLINK
, dl
->id
);
1482 case WEBKIT_DOWNLOAD_STATUS_CREATED
:
1483 cmd_html
= g_strdup_printf("<a href='%s%d/%d'>Start</a> / <a href='%s%d/%d'>Cancel</a>",
1484 xtp_prefix
, XT_XTP_DL_START
, dl
->id
, xtp_prefix
,
1485 XT_XTP_DL_CANCEL
, dl
->id
);
1486 status_html
= g_strdup_printf("Created");
1489 show_oops(t
, "%s: unknown download status", __func__
);
1492 destination
= webkit_download_get_destination_uri(dl
->download
);
1493 /* we might not have a destination set yet */
1495 destination
= webkit_download_get_suggested_filename(dl
->download
);
1496 d
= g_strdup(destination
); /* copy for basename */
1497 new_html
= g_strdup_printf(
1498 "%s\n<tr><td>%s</td><td>%s</td>"
1499 "<td style='text-align:center'>%s</td></tr>\n",
1500 html
, basename(d
), status_html
, cmd_html
);
1505 g_free(status_html
);
1515 /* cookie management XTP page */
1517 xtp_page_cl(struct tab
*t
, struct karg
*args
)
1519 char *body
, *page
, *tmp
;
1520 int i
= 1; /* all ids start 1 */
1522 GSList
*sc
, *pc
, *pc_start
;
1524 char *type
, *table_headers
, *last_domain
;
1526 DNPRINTF(XT_D_CMD
, "%s", __func__
);
1529 show_oops(NULL
, "%s invalid parameters", __func__
);
1533 generate_xtp_session_key(&t
->session_key
);
1536 table_headers
= g_strdup_printf("<table><tr>"
1539 "<th style='width:200px'>Value</th>"
1543 "<th>HTTP<br />only</th>"
1544 "<th style='width:40px'>Rm</th></tr>\n");
1546 sc
= soup_cookie_jar_all_cookies(s_cookiejar
);
1547 pc
= soup_cookie_jar_all_cookies(p_cookiejar
);
1550 body
= g_strdup_printf("<div align=\"center\"><a href=\"%s%d/%s/%d\">"
1551 "[ Remove All Cookies From All Domains ]</a></div>\n",
1552 XT_XTP_STR
, XT_XTP_CL
, t
->session_key
, XT_XTP_CL_REMOVE_ALL
);
1554 last_domain
= g_strdup("");
1555 for (; sc
; sc
= sc
->next
) {
1558 if (strcmp(last_domain
, c
->domain
) != 0) {
1561 g_free(last_domain
);
1562 last_domain
= g_strdup(c
->domain
);
1566 body
= g_strdup_printf("%s</table>"
1567 "<h2>%s</h2><div align=\"center\">"
1568 "<a href='%s%d/%s/%d/%d'>"
1569 "[ Remove All From This Domain ]"
1572 XT_XTP_STR
, XT_XTP_CL
, t
->session_key
,
1573 XT_XTP_CL_REMOVE_DOMAIN
, domain_id
,
1578 body
= g_strdup_printf("<h2>%s</h2>"
1579 "<div align=\"center\">"
1580 "<a href='%s%d/%s/%d/%d'>"
1581 "[ Remove All From This Domain ]</a></div>%s\n",
1582 c
->domain
, XT_XTP_STR
, XT_XTP_CL
,
1583 t
->session_key
, XT_XTP_CL_REMOVE_DOMAIN
,
1584 domain_id
, table_headers
);
1589 for (pc
= pc_start
; pc
; pc
= pc
->next
)
1590 if (soup_cookie_equal(pc
->data
, c
)) {
1591 type
= "Session + Persistent";
1596 body
= g_strdup_printf(
1599 "<td style='word-wrap:normal'>%s</td>"
1601 " <textarea rows='4'>%s</textarea>"
1607 "<td style='text-align:center'>"
1608 "<a href='%s%d/%s/%d/%d'>X</a></td></tr>\n",
1615 soup_date_to_string(c
->expires
, SOUP_DATE_COOKIE
) : "",
1630 soup_cookies_free(sc
);
1631 soup_cookies_free(pc
);
1633 /* small message if there are none */
1635 body
= g_strdup_printf("%s\n<tr><td style='text-align:center'"
1636 "colspan='8'>No Cookies</td></tr>\n", table_headers
);
1639 body
= g_strdup_printf("%s</table>", body
);
1642 page
= get_html_page("Cookie Jar", body
, "", TRUE
);
1644 g_free(table_headers
);
1645 g_free(last_domain
);
1647 load_webkit_string(t
, page
, XT_URI_ABOUT_COOKIEJAR
, 0);
1648 update_cookie_tabs(t
);
1656 xtp_page_hl(struct tab
*t
, struct karg
*args
)
1658 char *body
, *page
, *tmp
;
1660 int i
= 1; /* all ids start 1 */
1662 DNPRINTF(XT_D_CMD
, "%s", __func__
);
1665 show_oops(NULL
, "%s invalid parameters", __func__
);
1669 generate_xtp_session_key(&t
->session_key
);
1672 body
= g_strdup_printf("<div align=\"center\"><a href=\"%s%d/%s/%d\">"
1673 "[ Remove All ]</a></div>"
1674 "<table style='table-layout:fixed'><tr>"
1675 "<th>URI</th><th>Title</th><th>Last visited</th>"
1676 "<th style='width: 40px'>Rm</th></tr>\n",
1677 XT_XTP_STR
, XT_XTP_HL
, t
->session_key
, XT_XTP_HL_REMOVE_ALL
);
1679 RB_FOREACH_REVERSE(h
, history_list
, &hl
) {
1681 body
= g_strdup_printf(
1683 "<td><a href='%s'>%s</a></td>"
1686 "<td style='text-align: center'>"
1687 "<a href='%s%d/%s/%d/%d'>X</a></td></tr>\n",
1688 body
, h
->uri
, h
->uri
, h
->title
, ctime(&h
->time
),
1689 XT_XTP_STR
, XT_XTP_HL
, t
->session_key
,
1690 XT_XTP_HL_REMOVE
, i
);
1696 /* small message if there are none */
1699 body
= g_strdup_printf("%s\n<tr><td style='text-align:center'"
1700 "colspan='4'>No History</td></tr>\n", body
);
1705 body
= g_strdup_printf("%s</table>", body
);
1708 page
= get_html_page("History", body
, "", TRUE
);
1712 * update all history manager tabs as the xtp session
1713 * key has now changed. No need to update the current tab.
1714 * Already did that above.
1716 update_history_tabs(t
);
1718 load_webkit_string(t
, page
, XT_URI_ABOUT_HISTORY
, 0);
1725 * Generate a web page detailing the status of any downloads
1728 xtp_page_dl(struct tab
*t
, struct karg
*args
)
1730 struct download
*dl
;
1731 char *body
, *page
, *tmp
;
1735 DNPRINTF(XT_D_DOWNLOAD
, "%s", __func__
);
1738 show_oops(NULL
, "%s invalid parameters", __func__
);
1742 generate_xtp_session_key(&t
->session_key
);
1744 /* header - with refresh so as to update */
1745 if (refresh_interval
>= 1)
1746 ref
= g_strdup_printf(
1747 "<meta http-equiv='refresh' content='%u"
1748 ";url=%s%d/%s/%d' />\n",
1757 body
= g_strdup_printf("<div align='center'>"
1758 "<p>\n<a href='%s%d/%s/%d'>\n[ Refresh Downloads ]</a>\n"
1759 "</p><table><tr><th style='width: 60%%'>"
1760 "File</th>\n<th>Progress</th><th>Command</th></tr>\n",
1761 XT_XTP_STR
, XT_XTP_DL
, t
->session_key
, XT_XTP_DL_LIST
);
1763 RB_FOREACH_REVERSE(dl
, download_list
, &downloads
) {
1764 body
= xtp_page_dl_row(t
, body
, dl
);
1768 /* message if no downloads in list */
1771 body
= g_strdup_printf("%s\n<tr><td colspan='3'"
1772 " style='text-align: center'>"
1773 "No downloads</td></tr>\n", body
);
1778 body
= g_strdup_printf("%s</table></div>", body
);
1781 page
= get_html_page("Downloads", body
, ref
, 1);
1786 * update all download manager tabs as the xtp session
1787 * key has now changed. No need to update the current tab.
1788 * Already did that above.
1790 update_download_tabs(t
);
1792 load_webkit_string(t
, page
, XT_URI_ABOUT_DOWNLOADS
, 0);
1799 xtp_page_sl(struct tab
*t
, struct karg
*args
)
1802 char *page
, *body
, *tmp
;
1804 DNPRINTF(XT_D_SEARCH
, "%s", __func__
);
1806 generate_xtp_session_key(&t
->session_key
);
1809 show_oops(NULL
, "%s invalid parameters", __func__
);
1813 body
= g_strdup_printf("<p>The xombrero authors will not choose a "
1814 "default search engine for you. What follows is a list of search "
1815 "engines (in no particular order) you may be interested in. "
1816 "To permanently choose a search engine, click [ Select ] to save "
1817 "<tt>search_string</tt> as a runtime setting, or set "
1818 "<tt>search_string</tt> to the appropriate URL in your xombrero "
1819 "configuration.</p>");
1822 body
= g_strdup_printf("%s\n<table style='table-layout:fixed'><tr>"
1823 "<th style='width: 200px'>Name</th><th>URL</th>"
1824 "<th style='width: 100px'>Select</th></tr>\n", body
);
1827 for (i
= 0; i
< (sizeof search_list
/ sizeof (struct search_type
)); ++i
)
1828 body
= search_engine_add(body
, search_list
[i
].name
,
1829 search_list
[i
].url
, t
->session_key
, i
);
1832 body
= g_strdup_printf("%s</table>", body
);
1835 page
= get_html_page("Choose a search engine", body
, "", 1);
1839 * update all search tabs as the xtp session key has now changed. No
1840 * need to update the current tab. Already did that above.
1842 update_search_tabs(t
);
1844 load_webkit_string(t
, page
, XT_URI_ABOUT_SEARCH
, 0);
1851 xtp_page_sv(struct tab
*t
, struct karg
*args
)
1855 struct secviolation find
, *sv
;
1859 show_oops(NULL
, "secviolation invalid parameters");
1863 generate_xtp_session_key(&t
->session_key
);
1866 find
.xtp_arg
= t
->xtp_arg
;
1867 sv
= RB_FIND(secviolation_list
, &svl
, &find
);
1871 sv
= g_malloc(sizeof(struct secviolation
));
1872 sv
->xtp_arg
= ++arg
;
1876 RB_INSERT(secviolation_list
, &svl
, sv
);
1879 if (sv
->uri
== NULL
|| (soupuri
= soup_uri_new(sv
->uri
)) == NULL
)
1882 body
= g_strdup_printf(
1883 "<p><b>You tried to access %s</b>."
1884 "<p><b>The site's security certificate has been modified.</b>"
1885 "<p>The domain of the page you have tried to access, <b>%s</b>, "
1886 "has a different remote certificate then the local cached version "
1887 "from a previous visit. As a security precaution to help prevent "
1888 "against man-in-the-middle attacks, please choose one of the "
1889 "following actions to continue, or disable the "
1890 "<tt>warn_cert_changes</tt> setting in your xombrero "
1892 "<p><b>Choose an action:"
1893 "<br><a href='%s%d/%s/%d/%d'>Allow for this session</a>"
1894 "<br><a href='%s%d/%s/%d/%d'>Cache new certificate</a>"
1895 "<br><a href='%s%d/%s/%d/%d'>Show cached certificate</a>"
1896 "<br><a href='%s%d/%s/%d/%d'>Show new certificate</a>",
1899 XT_XTP_STR
, XT_XTP_SV
, t
->session_key
, XT_XTP_SV_ALLOW_SESSION
,
1901 XT_XTP_STR
, XT_XTP_SV
, t
->session_key
, XT_XTP_SV_CACHE
,
1903 XT_XTP_STR
, XT_XTP_SV
, t
->session_key
, XT_XTP_SV_SHOW_CACHED_CERT
,
1905 XT_XTP_STR
, XT_XTP_SV
, t
->session_key
, XT_XTP_SV_SHOW_NEW_CERT
,
1908 page
= get_html_page("Security Violation", body
, "", 0);
1911 load_webkit_string(t
, page
, XT_URI_ABOUT_SECVIOLATION
, 1);
1915 soup_uri_free(soupuri
);
1921 startpage(struct tab
*t
, struct karg
*args
)
1923 char *page
, *body
, *b
;
1927 show_oops(NULL
, "startpage invalid parameters");
1929 body
= g_strdup_printf("<b>Startup Exception(s):</b><p>");
1931 TAILQ_FOREACH(s
, &spl
, entry
) {
1933 body
= g_strdup_printf("%s%s<br>", body
, s
->line
);
1937 page
= get_html_page("Startup Exception", body
, "", 0);
1940 load_webkit_string(t
, page
, XT_URI_ABOUT_STARTPAGE
, 0);
1947 startpage_add(const char *fmt
, ...)
1957 if ((msg
= g_strdup_vprintf(fmt
, ap
)) == NULL
)
1958 errx(1, "startpage_add failed");
1961 s
= g_malloc0(sizeof *s
);
1964 TAILQ_INSERT_TAIL(&spl
, s
, entry
);
1966 gchar
*show_g_object_settings(GObject
*, char *, int);
1969 xt_g_object_serialize(GValue
*value
, const gchar
*tname
, char *str
, int recurse
)
1972 char *valstr
, *tmpstr
, *tmpsettings
;
1975 typeno
= G_TYPE_FUNDAMENTAL( G_VALUE_TYPE(value
) );
1978 valstr
= g_strdup_printf("%d",
1979 g_value_get_enum(value
));
1982 valstr
= g_strdup_printf("%c",
1983 #if GLIB_CHECK_VERSION(2, 32, 0)
1984 g_value_get_schar(value
));
1986 g_value_get_char(value
));
1990 valstr
= g_strdup_printf("%c",
1991 g_value_get_uchar(value
));
1994 valstr
= g_strdup_printf("%ld",
1995 g_value_get_long(value
));
1998 valstr
= g_strdup_printf("%ld",
1999 g_value_get_ulong(value
));
2002 valstr
= g_strdup_printf("%d",
2003 g_value_get_int(value
));
2006 valstr
= g_strdup_printf("%" PRIo64
,
2007 (int64_t) g_value_get_int64(value
));
2010 valstr
= g_strdup_printf("%d",
2011 g_value_get_uint(value
));
2014 valstr
= g_strdup_printf("%" PRIu64
,
2015 (uint64_t) g_value_get_uint64(value
));
2018 valstr
= g_strdup_printf("0x%x",
2019 g_value_get_flags(value
));
2021 case G_TYPE_BOOLEAN
:
2022 valstr
= g_strdup_printf("%s",
2023 g_value_get_boolean(value
) ? "TRUE" : "FALSE");
2026 valstr
= g_strdup_printf("%f",
2027 g_value_get_float(value
));
2030 valstr
= g_strdup_printf("%f",
2031 g_value_get_double(value
));
2034 valstr
= g_strdup_printf("\"%s\"",
2035 g_value_get_string(value
));
2037 case G_TYPE_POINTER
:
2038 valstr
= g_strdup_printf("%p",
2039 g_value_get_pointer(value
));
2042 object
= g_value_get_object(value
);
2043 if (object
!= NULL
) {
2045 tmpstr
= g_strdup_printf("%s ", str
);
2046 tmpsettings
= show_g_object_settings( object
,
2050 if (strrchr(tmpsettings
, '\n') != NULL
) {
2051 valstr
= g_strdup_printf("%s%s }",
2053 g_free(tmpsettings
);
2055 valstr
= tmpsettings
;
2058 valstr
= g_strdup_printf("<...>");
2061 valstr
= g_strdup_printf("settings[] = NULL");
2065 valstr
= g_strdup_printf("type %s unhandled", tname
);
2071 show_g_object_settings(GObject
*o
, char *str
, int recurse
)
2073 char *b
, *p
, *body
, *valstr
, *tmpstr
;
2079 GParamSpec
**proplist
;
2082 if (!G_IS_OBJECT(o
)) {
2083 fprintf(stderr
, "%s is not a g_object\n", str
);
2084 return g_strdup("");
2086 proplist
= g_object_class_list_properties(
2087 G_OBJECT_GET_CLASS(o
), &n_props
);
2089 if (GTK_IS_WIDGET(o
)) {
2090 name
= gtk_widget_get_name(GTK_WIDGET(o
));
2095 body
= g_strdup_printf("%s[0] = { }", name
);
2096 goto end_show_g_objects
;
2099 body
= g_strdup_printf("%s[%d] = {\n", name
, n_props
);
2100 for (i
=0; i
< n_props
; i
++) {
2101 pspec
= proplist
[i
];
2102 tname
= G_OBJECT_TYPE_NAME(pspec
);
2103 bzero(&value
, sizeof value
);
2106 if (!(pspec
->flags
& G_PARAM_READABLE
))
2107 valstr
= g_strdup_printf("not a readable property");
2109 g_value_init(&value
, G_PARAM_SPEC_VALUE_TYPE(pspec
));
2110 g_object_get_property(G_OBJECT(o
), pspec
->name
,
2112 typeno
= G_TYPE_FUNDAMENTAL( G_VALUE_TYPE(&value
) );
2115 /* based on the type, recurse and display values */
2116 if (valstr
== NULL
) {
2117 valstr
= xt_g_object_serialize(&value
, tname
, str
,
2121 tmpstr
= g_strdup_printf("%-13s %s%s%s,", tname
, pspec
->name
,
2122 (typeno
== G_TYPE_OBJECT
) ? "." : " = ", valstr
);
2125 #define XT_G_OBJECT_SPACING 50
2126 p
= strrchr(tmpstr
, '\n');
2127 if (p
== NULL
&& strlen(tmpstr
) > XT_G_OBJECT_SPACING
) {
2128 body
= g_strdup_printf(
2129 "%s%s %-50s\n%s %50s /* %3d flags=0x%08x */\n",
2130 body
, str
, tmpstr
, str
, "", i
, pspec
->flags
);
2135 strspaces
= XT_G_OBJECT_SPACING
;
2137 strspaces
= strlen(tmpstr
) - (strlen(p
) - strlen(str
)) + XT_G_OBJECT_SPACING
+ 5;
2138 fmt
= g_strdup_printf("%%s%%s %%-%ds /* %%3d flags=0x%%08x */\n", strspaces
);
2139 body
= g_strdup_printf(fmt
, body
, str
, tmpstr
, i
, pspec
->flags
);
2152 xt_append_settings(char *str
, GObject
*object
, char *name
, int recurse
)
2154 char *newstr
, *settings
;
2156 settings
= show_g_object_settings(object
, name
, recurse
);
2160 newstr
= g_strdup_printf("%s%s %s%s };\n", str
, name
, settings
, name
);
2167 about_webkit(struct tab
*t
, struct karg
*arg
)
2169 char *page
, *body
, *settingstr
;
2171 settingstr
= xt_append_settings(NULL
, G_OBJECT(t
->settings
),
2173 body
= g_strdup_printf("<pre>%s</pre>\n", settingstr
);
2176 page
= get_html_page("About Webkit", body
, "", 0);
2179 load_webkit_string(t
, page
, XT_URI_ABOUT_WEBKIT
, 0);
2185 static int toplevelcount
= 0;
2188 xt_append_toplevel(GtkWindow
*w
, char **body
)
2192 n
= g_strdup_printf("toplevel#%d", toplevelcount
++);
2193 *body
= xt_append_settings(*body
, G_OBJECT(w
), n
, 0);
2198 allthethings(struct tab
*t
, struct karg
*arg
)
2201 char *page
, *body
, *b
;
2203 body
= xt_append_settings(NULL
, G_OBJECT(t
->wv
), "t->wv", 1);
2204 body
= xt_append_settings(body
, G_OBJECT(t
->inspector
),
2206 #if 0 /* not until warnings are gone */
2207 body
= xt_append_settings(body
, G_OBJECT(session
),
2211 list
= gtk_window_list_toplevels();
2212 g_list_foreach(list
, (GFunc
)g_object_ref
, NULL
);
2213 g_list_foreach(list
, (GFunc
)xt_append_toplevel
, &body
);
2214 g_list_foreach(list
, (GFunc
)g_object_unref
, NULL
);
2218 body
= g_strdup_printf("<pre>%scan paste clipboard = %d\n</pre>", body
,
2219 webkit_web_view_can_paste_clipboard(t
->wv
));
2222 page
= get_html_page("About All The Things _o/", body
, "", 0);
2225 load_webkit_string(t
, page
, XT_URI_ABOUT_ALLTHETHINGS
, 0);