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" \
63 /* XTP classes (xxxt://<class>) */
64 #define XT_XTP_INVALID (0) /* invalid */
65 #define XT_XTP_DL (1) /* downloads */
66 #define XT_XTP_HL (2) /* history */
67 #define XT_XTP_CL (3) /* cookies */
68 #define XT_XTP_FL (4) /* favorites */
69 #define XT_XTP_SL (5) /* search */
70 #define XT_XTP_AB (6) /* about */
71 #define XT_XTP_SV (7) /* security violation */
73 /* XTP download actions */
74 #define XT_XTP_DL_LIST (1)
75 #define XT_XTP_DL_CANCEL (2)
76 #define XT_XTP_DL_REMOVE (3)
77 #define XT_XTP_DL_UNLINK (4)
78 #define XT_XTP_DL_START (5)
80 /* XTP history actions */
81 #define XT_XTP_HL_LIST (1)
82 #define XT_XTP_HL_REMOVE (2)
83 #define XT_XTP_HL_REMOVE_ALL (3)
85 /* XTP cookie actions */
86 #define XT_XTP_CL_LIST (1)
87 #define XT_XTP_CL_REMOVE (2)
88 #define XT_XTP_CL_REMOVE_DOMAIN (3)
89 #define XT_XTP_CL_REMOVE_ALL (4)
91 /* XTP cookie actions */
92 #define XT_XTP_FL_LIST (1)
93 #define XT_XTP_FL_REMOVE (2)
95 /* XPT search actions */
96 #define XT_XTP_SL_SET (1)
98 /* XPT about actions */
99 #define XT_XTP_AB_EDIT_CONF (1)
101 /* XTP security violation actions */
102 #define XT_XTP_SV_SHOW_CERT (1)
103 #define XT_XTP_SV_ALLOW_SESSION (2)
104 #define XT_XTP_SV_CACHE (3)
106 int js_show_wl(struct tab
*, struct karg
*);
107 int pl_show_wl(struct tab
*, struct karg
*);
108 int set(struct tab
*, struct karg
*);
109 int marco(struct tab
*, struct karg
*);
110 int startpage(struct tab
*, struct karg
*);
111 const char * marco_message(int *);
112 void update_cookie_tabs(struct tab
*apart_from
);
113 int about_webkit(struct tab
*, struct karg
*);
114 int allthethings(struct tab
*, struct karg
*);
116 struct about_type about_list
[] = {
117 { XT_URI_ABOUT_ABOUT
, xtp_page_ab
},
118 { XT_URI_ABOUT_ALLTHETHINGS
, allthethings
},
119 { XT_URI_ABOUT_BLANK
, blank
},
120 { XT_URI_ABOUT_CERTS
, ca_cmd
},
121 { XT_URI_ABOUT_COOKIEWL
, cookie_show_wl
},
122 { XT_URI_ABOUT_COOKIEJAR
, xtp_page_cl
},
123 { XT_URI_ABOUT_DOWNLOADS
, xtp_page_dl
},
124 { XT_URI_ABOUT_FAVORITES
, xtp_page_fl
},
125 { XT_URI_ABOUT_HELP
, help
},
126 { XT_URI_ABOUT_HISTORY
, xtp_page_hl
},
127 { XT_URI_ABOUT_JSWL
, js_show_wl
},
128 { XT_URI_ABOUT_SET
, set
},
129 { XT_URI_ABOUT_STATS
, stats
},
130 { XT_URI_ABOUT_MARCO
, marco
},
131 { XT_URI_ABOUT_STARTPAGE
, startpage
},
132 { XT_URI_ABOUT_PLUGINWL
, pl_show_wl
},
133 { XT_URI_ABOUT_WEBKIT
, about_webkit
},
134 { XT_URI_ABOUT_SEARCH
, xtp_page_sl
},
135 { XT_URI_ABOUT_SECVIOLATION
, NULL
},
142 { "Google (SSL)", "https://encrypted.google.com/search?q=%s&&client=xombrero" },
143 { "Bing", "http://www.bing.com/search?q=%s" },
144 { "Yahoo", "http://search.yahoo.com/search?p=%s" },
145 { "DuckDuckGo", "https://duckduckgo.com/?q=%s" },
146 { "DuckDuckGo (HTML)", "https://duckduckgo.com/html?q=%s" },
147 { "DuckDuckGo (Lite)", "https://duckduckgo.com/lite?q=%s" },
148 { "Ixquick", "https://ixquick.com/do/search?q=%s" },
149 { "Startpage", "https://startpage.com/do/search?q=%s" },
154 * We use these to prevent people putting xxxt:// URLs on
155 * websites in the wild. We generate 8 bytes and represent in hex (16 chars)
157 #define XT_XTP_SES_KEY_SZ 8
158 #define XT_XTP_SES_KEY_HEX_FMT \
159 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8 "%02" PRIx8
161 char *dl_session_key
; /* downloads */
162 char *hl_session_key
; /* history list */
163 char *cl_session_key
; /* cookie list */
164 char *fl_session_key
; /* favorites list */
165 char *sl_session_key
; /* search */
166 char *ab_session_key
; /* about */
167 char *sv_session_key
; /* secviolation */
169 int updating_ab_tabs
= 0;
170 int updating_fl_tabs
= 0;
171 int updating_dl_tabs
= 0;
172 int updating_hl_tabs
= 0;
173 int updating_cl_tabs
= 0;
174 int updating_sl_tabs
= 0;
175 int updating_sv_tabs
= 0;
176 struct download_list downloads
;
179 about_list_size(void)
181 return (LENGTH(about_list
));
185 get_html_page(gchar
*title
, gchar
*body
, gchar
*head
, bool addstyles
)
189 r
= g_strdup_printf(XT_DOCTYPE XT_HTML_TAG
191 "<title>%s</title>\n"
200 addstyles
? XT_PAGE_STYLE
: "",
209 * Display a web page from a HTML string in memory, rather than from a URL
212 load_webkit_string(struct tab
*t
, const char *str
, gchar
*title
)
217 /* we set this to indicate we want to manually do navaction */
219 t
->item
= webkit_web_back_forward_list_get_current_item(t
->bfl
);
221 t
->xtp_meaning
= XT_XTP_TAB_MEANING_NORMAL
;
223 /* set t->xtp_meaning */
224 for (i
= 0; i
< LENGTH(about_list
); i
++)
225 if (!strcmp(title
, about_list
[i
].name
)) {
230 webkit_web_view_load_string(t
->wv
, str
, NULL
, encoding
,
232 #if GTK_CHECK_VERSION(2, 20, 0)
233 gtk_spinner_stop(GTK_SPINNER(t
->spinner
));
234 gtk_widget_hide(t
->spinner
);
236 snprintf(file
, sizeof file
, "%s" PS
"%s", resource_dir
, icons
[0]);
237 xt_icon_from_file(t
, file
);
242 blank(struct tab
*t
, struct karg
*args
)
245 show_oops(NULL
, "blank invalid parameters");
247 load_webkit_string(t
, "", XT_URI_ABOUT_BLANK
);
253 help(struct tab
*t
, struct karg
*args
)
255 char *page
, *head
, *body
;
258 show_oops(NULL
, "help invalid parameters");
260 head
= "<meta http-equiv=\"REFRESH\" content=\"0;"
261 "url=http://opensource.conformal.com/cgi-bin/man-cgi?xombrero\">"
263 body
= "xombrero man page <a href=\"http://opensource.conformal.com/"
264 "cgi-bin/man-cgi?xombrero\">http://opensource.conformal.com/"
265 "cgi-bin/man-cgi?xombrero</a>";
267 page
= get_html_page(XT_NAME
, body
, head
, FALSE
);
269 load_webkit_string(t
, page
, XT_URI_ABOUT_HELP
);
276 stats(struct tab
*t
, struct karg
*args
)
278 char *page
, *body
, *s
, line
[64 * 1024];
279 uint64_t line_count
= 0;
283 show_oops(NULL
, "stats invalid parameters");
286 if (save_rejected_cookies
) {
287 if ((r_cookie_f
= fopen(rc_fname
, "r"))) {
289 s
= fgets(line
, sizeof line
, r_cookie_f
);
290 if (s
== NULL
|| feof(r_cookie_f
) ||
296 snprintf(line
, sizeof line
,
297 "<br/>Cookies blocked(*) total: %" PRIu64
,
300 show_oops(t
, "Can't open blocked cookies file: %s",
304 body
= g_strdup_printf(
305 "Cookies blocked(*) this session: %" PRIu64
307 "<p><small><b>*</b> results vary based on settings</small></p>",
311 page
= get_html_page("Statistics", body
, "", 0);
314 load_webkit_string(t
, page
, XT_URI_ABOUT_STATS
);
321 show_certs(struct tab
*t
, gnutls_x509_crt_t
*certs
,
322 size_t cert_count
, char *title
)
324 gnutls_datum_t cinfo
;
330 for (i
= 0; i
< cert_count
; i
++) {
331 if (gnutls_x509_crt_print(certs
[i
], GNUTLS_CRT_PRINT_FULL
,
336 body
= g_strdup_printf("%s<h2>Cert #%d</h2><pre>%s</pre>",
337 body
, i
, cinfo
.data
);
338 gnutls_free(cinfo
.data
);
342 tmp
= get_html_page(title
, body
, "", 0);
345 load_webkit_string(t
, tmp
, XT_URI_ABOUT_CERTS
);
350 ca_cmd(struct tab
*t
, struct karg
*args
)
353 int rv
= 1, certs
= 0, certs_read
;
356 gnutls_x509_crt_t
*c
= NULL
;
357 char *certs_buf
= NULL
, *s
;
359 if ((f
= fopen(ssl_ca_file
, "r")) == NULL
) {
360 show_oops(t
, "Can't open CA file: %s", ssl_ca_file
);
364 if (fstat(fileno(f
), &sb
) == -1) {
365 show_oops(t
, "Can't stat CA file: %s", ssl_ca_file
);
369 certs_buf
= g_malloc(sb
.st_size
+ 1);
370 if (fread(certs_buf
, 1, sb
.st_size
, f
) != sb
.st_size
) {
371 show_oops(t
, "Can't read CA file: %s", strerror(errno
));
374 certs_buf
[sb
.st_size
] = '\0';
377 while ((s
= strstr(s
, "BEGIN CERTIFICATE"))) {
379 s
+= strlen("BEGIN CERTIFICATE");
382 bzero(&dt
, sizeof dt
);
383 dt
.data
= (unsigned char *)certs_buf
;
384 dt
.size
= sb
.st_size
;
385 c
= g_malloc(sizeof(gnutls_x509_crt_t
) * certs
);
386 certs_read
= gnutls_x509_crt_list_import(c
, (unsigned int *)&certs
, &dt
,
387 GNUTLS_X509_FMT_PEM
, 0);
388 if (certs_read
<= 0) {
389 show_oops(t
, "No cert(s) available");
392 show_certs(t
, c
, certs_read
, "Certificate Authority Certificates");
405 cookie_show_wl(struct tab
*t
, struct karg
*args
)
407 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
408 wl_show(t
, args
, "Cookie White List", &c_wl
);
414 js_show_wl(struct tab
*t
, struct karg
*args
)
416 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
417 wl_show(t
, args
, "JavaScript White List", &js_wl
);
423 cookie_cmd(struct tab
*t
, struct karg
*args
)
425 if (args
->i
& XT_SHOW
)
426 wl_show(t
, args
, "Cookie White List", &c_wl
);
427 else if (args
->i
& XT_WL_TOGGLE
) {
428 args
->i
|= XT_WL_RELOAD
;
430 } else if (args
->i
& XT_SAVE
) {
431 args
->i
|= XT_WL_RELOAD
;
432 wl_save(t
, args
, XT_WL_COOKIE
);
433 } else if (args
->i
& XT_DELETE
) {
435 update_cookie_tabs(NULL
);
442 js_cmd(struct tab
*t
, struct karg
*args
)
444 if (args
->i
& XT_SHOW
)
445 wl_show(t
, args
, "JavaScript White List", &js_wl
);
446 else if (args
->i
& XT_SAVE
) {
447 args
->i
|= XT_WL_RELOAD
;
448 wl_save(t
, args
, XT_WL_JAVASCRIPT
);
449 } else if (args
->i
& XT_WL_TOGGLE
) {
450 args
->i
|= XT_WL_RELOAD
;
452 } else if (args
->i
& XT_DELETE
)
453 show_oops(t
, "'js delete' currently unimplemented");
459 pl_show_wl(struct tab
*t
, struct karg
*args
)
461 args
->i
= XT_SHOW
| XT_WL_PERSISTENT
| XT_WL_SESSION
;
462 wl_show(t
, args
, "Plugin White List", &pl_wl
);
468 pl_cmd(struct tab
*t
, struct karg
*args
)
470 if (args
->i
& XT_SHOW
)
471 wl_show(t
, args
, "Plugin White List", &pl_wl
);
472 else if (args
->i
& XT_SAVE
) {
473 args
->i
|= XT_WL_RELOAD
;
474 wl_save(t
, args
, XT_WL_PLUGIN
);
475 } else if (args
->i
& XT_WL_TOGGLE
) {
476 args
->i
|= XT_WL_RELOAD
;
478 } else if (args
->i
& XT_DELETE
)
479 show_oops(t
, "'plugin delete' currently unimplemented");
485 * cancel, remove, etc. downloads
488 xtp_handle_dl(struct tab
*t
, uint8_t cmd
, int id
)
490 struct download find
, *d
= NULL
;
493 const char *uri
= NULL
;
496 DNPRINTF(XT_D_DOWNLOAD
, "download control: cmd %d, id %d\n", cmd
, id
);
498 /* some commands require a valid download id */
499 if (cmd
!= XT_XTP_DL_LIST
) {
500 /* lookup download in question */
502 d
= RB_FIND(download_list
, &downloads
, &find
);
505 show_oops(t
, "%s: no such download", __func__
);
510 /* decide what to do */
512 case XT_XTP_DL_START
:
513 /* our downloads always needs to be
514 * restarted if called from here
516 download_start(t
, d
, XT_DL_RESTART
);
518 case XT_XTP_DL_CANCEL
:
519 webkit_download_cancel(d
->download
);
520 g_object_unref(d
->download
);
521 RB_REMOVE(download_list
, &downloads
, d
);
523 case XT_XTP_DL_UNLINK
:
525 /* XXX uri's aren't handled properly on windows? */
526 unlink(webkit_download_get_destination_uri(d
->download
));
528 uri
= webkit_download_get_destination_uri(d
->download
);
529 if ((file
= g_filename_from_uri(uri
, NULL
, NULL
)) != NULL
) {
535 case XT_XTP_DL_REMOVE
:
536 webkit_download_cancel(d
->download
); /* just incase */
537 g_object_unref(d
->download
);
538 RB_REMOVE(download_list
, &downloads
, d
);
544 show_oops(t
, "%s: unknown command", __func__
);
547 xtp_page_dl(t
, NULL
);
551 xtp_handle_hl(struct tab
*t
, uint8_t cmd
, int id
)
553 struct history
*h
, *next
, *ht
;
557 case XT_XTP_HL_REMOVE
:
558 /* walk backwards, as listed in reverse */
559 for (h
= RB_MAX(history_list
, &hl
); h
!= NULL
; h
= next
) {
560 next
= RB_PREV(history_list
, &hl
, h
);
562 RB_REMOVE(history_list
, &hl
, h
);
563 g_free((gpointer
) h
->title
);
564 g_free((gpointer
) h
->uri
);
571 case XT_XTP_HL_REMOVE_ALL
:
572 RB_FOREACH_SAFE(h
, history_list
, &hl
, ht
)
573 RB_REMOVE(history_list
, &hl
, h
);
576 /* Nothing - just xtp_page_hl() below */
579 show_oops(t
, "%s: unknown command", __func__
);
583 xtp_page_hl(t
, NULL
);
586 /* remove a favorite */
588 remove_favorite(struct tab
*t
, int index
)
590 char file
[PATH_MAX
], *title
, *uri
= NULL
;
591 char *new_favs
, *tmp
;
597 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_FAVS_FILE
);
599 if ((f
= fopen(file
, "r")) == NULL
) {
600 show_oops(t
, "%s: can't open favorites: %s",
601 __func__
, strerror(errno
));
605 /* build a string which will become the new favroites file */
606 new_favs
= g_strdup("");
609 if ((title
= fparseln(f
, &len
, &lineno
, NULL
, 0)) == NULL
)
610 if (feof(f
) || ferror(f
))
612 /* XXX THIS IS NOT THE RIGHT HEURISTIC */
619 if ((uri
= fparseln(f
, &len
, &lineno
, NULL
, 0)) == NULL
) {
620 if (feof(f
) || ferror(f
)) {
621 show_oops(t
, "%s: can't parse favorites %s",
622 __func__
, strerror(errno
));
627 /* as long as this isn't the one we are deleting add to file */
630 new_favs
= g_strdup_printf("%s%s\n%s\n",
631 new_favs
, title
, uri
);
643 /* write back new favorites file */
644 if ((f
= fopen(file
, "w")) == NULL
) {
645 show_oops(t
, "%s: can't open favorites: %s",
646 __func__
, strerror(errno
));
650 if (fwrite(new_favs
, strlen(new_favs
), 1, f
) != 1)
651 show_oops(t
, "%s: can't fwrite", __func__
);
664 add_favorite(struct tab
*t
, struct karg
*args
)
669 size_t urilen
, linelen
;
670 const gchar
*uri
, *title
;
675 /* don't allow adding of xtp pages to favorites */
676 if (t
->xtp_meaning
!= XT_XTP_TAB_MEANING_NORMAL
) {
677 show_oops(t
, "%s: can't add xtp pages to favorites", __func__
);
681 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_FAVS_FILE
);
682 if ((f
= fopen(file
, "r+")) == NULL
) {
683 show_oops(t
, "Can't open favorites file: %s", strerror(errno
));
687 title
= get_title(t
, FALSE
);
690 if (title
== NULL
|| uri
== NULL
) {
691 show_oops(t
, "can't add page to favorites");
695 urilen
= strlen(uri
);
698 if ((line
= fparseln(f
, &linelen
, NULL
, NULL
, 0)) == NULL
)
699 if (feof(f
) || ferror(f
))
702 if (linelen
== urilen
&& !strcmp(line
, uri
))
709 fprintf(f
, "\n%s\n%s", title
, uri
);
715 update_favorite_tabs(NULL
);
721 search_engine_add(char *body
, const char *name
, const char *url
, int select
)
725 body
= g_strdup_printf("%s<tr>"
728 "<td style='text-align: center'>"
729 "<a href='%s%d/%s/%d/%d'>[ Select ]</a></td>"
734 XT_XTP_STR
, XT_XTP_SL
, sl_session_key
, XT_XTP_SL_SET
, select
);
740 xtp_handle_ab(struct tab
*t
, uint8_t cmd
, int arg
)
742 char config
[PATH_MAX
];
747 case XT_XTP_AB_EDIT_CONF
:
748 if (external_editor
== NULL
|| strlen(external_editor
) == 0) {
749 show_oops(t
, "external_editor is unset");
753 snprintf(config
, sizeof config
, "%s" PS
".%s", pwd
->pw_dir
,
755 sv
= g_strsplit(external_editor
, "<file>", -1);
756 cmdstr
= g_strjoinv(config
, sv
);
758 sv
= g_strsplit_set(cmdstr
, " \t", -1);
760 if (!g_spawn_async(NULL
, sv
, NULL
, G_SPAWN_SEARCH_PATH
, NULL
, NULL
,
762 show_oops(t
, "%s: could not spawn process", __func__
);
768 show_oops(t
, "%s, invalid about command", __func__
);
771 xtp_page_ab(t
, NULL
);
774 xtp_handle_fl(struct tab
*t
, uint8_t cmd
, int arg
)
778 /* nothing, just the below call to xtp_page_fl() */
780 case XT_XTP_FL_REMOVE
:
781 remove_favorite(t
, arg
);
784 show_oops(t
, "%s: invalid favorites command", __func__
);
788 xtp_page_fl(t
, NULL
);
792 xtp_handle_cl(struct tab
*t
, uint8_t cmd
, int arg
)
796 /* nothing, just xtp_page_cl() */
798 case XT_XTP_CL_REMOVE
:
801 case XT_XTP_CL_REMOVE_DOMAIN
:
802 remove_cookie_domain(arg
);
804 case XT_XTP_CL_REMOVE_ALL
:
808 show_oops(t
, "%s: unknown cookie xtp command", __func__
);
812 xtp_page_cl(t
, NULL
);
816 xtp_handle_sl(struct tab
*t
, uint8_t cmd
, int arg
)
824 char delim
[3] = { '\0', '\0', '\0' };
825 char *line
, *lt
, *enc_search
, *uri
;
826 char *contents
, *tmp
;
831 set_search_string((char *)search_list
[arg
].url
);
832 if (runtime_settings
== NULL
|| strlen(runtime_settings
) == 0) {
833 show_oops(t
, "could not set search_string in "
837 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
,
839 if (stat(file
, &sb
) || (f
= fopen(file
, "r+")) == NULL
) {
840 show_oops(t
, "could not set search_string in runtime");
843 lt
= g_strdup_printf("search_string=%s",
844 (char *)search_list
[arg
].url
);
845 contents
= g_strdup("");
847 line
= fparseln(f
, &linelen
, NULL
, delim
, 0);
848 if (line
== NULL
|| linelen
== 0)
851 if (strstr(line
, "search_string=") == NULL
)
852 contents
= g_strdup_printf("%s%s\n", contents
,
856 contents
= g_strdup_printf("%s%s\n", contents
,
865 contents
= g_strdup_printf("%s%s\n", contents
, lt
);
868 if ((f
= freopen(file
, "w", f
)) == NULL
)
869 show_oops(t
, "could not set search_string in runtime");
878 show_oops(t
, "%s: unknown search xtp command", __func__
);
882 search
= gtk_entry_get_text(GTK_ENTRY(t
->search_entry
)); /* static */
883 enc_search
= soup_uri_encode(search
, XT_RESERVED_CHARS
);
884 sv
= g_strsplit(search_string
, "%s", 2);
885 uri
= g_strjoinv(enc_search
, sv
);
893 xtp_handle_sv(struct tab
*t
, uint8_t cmd
, int id
)
895 SoupURI
*soupuri
= NULL
;
896 struct karg args
= {0};
897 struct secviolation find
, *sv
;
898 struct sv_ignore
*svi
= NULL
;
901 if ((sv
= RB_FIND(secviolation_list
, &svl
, &find
)) == NULL
)
904 args
.ptr
= (void *)sv
->t
;
908 case XT_XTP_SV_SHOW_CERT
:
912 case XT_XTP_SV_ALLOW_SESSION
:
913 soupuri
= soup_uri_new(sv
->uri
);
914 svi
= malloc(sizeof(struct sv_ignore
));
915 svi
->domain
= g_strdup(soupuri
->host
);
916 RB_INSERT(sv_ignore_list
, &svil
, svi
);
917 load_uri(t
, sv
->uri
);
920 case XT_XTP_SV_CACHE
:
923 load_uri(t
, sv
->uri
);
927 show_oops(t
, "%s: invalid secviolation command", __func__
);
933 soup_uri_free(soupuri
);
934 RB_REMOVE(secviolation_list
, &svl
, sv
);
937 /* link an XTP class to it's session key and handler function */
938 struct xtp_despatch
{
941 void (*handle_func
)(struct tab
*, uint8_t, int);
944 struct xtp_despatch xtp_despatches
[] = {
945 { XT_XTP_DL
, &dl_session_key
, xtp_handle_dl
},
946 { XT_XTP_HL
, &hl_session_key
, xtp_handle_hl
},
947 { XT_XTP_FL
, &fl_session_key
, xtp_handle_fl
},
948 { XT_XTP_CL
, &cl_session_key
, xtp_handle_cl
},
949 { XT_XTP_SL
, &sl_session_key
, xtp_handle_sl
},
950 { XT_XTP_AB
, &ab_session_key
, xtp_handle_ab
},
951 { XT_XTP_SV
, &sv_session_key
, xtp_handle_sv
},
952 { XT_XTP_INVALID
, NULL
, NULL
}
956 * generate a session key to secure xtp commands.
957 * pass in a ptr to the key in question and it will
958 * be modified in place.
961 generate_xtp_session_key(char **key
)
963 uint8_t rand_bytes
[XT_XTP_SES_KEY_SZ
];
970 arc4random_buf(rand_bytes
, XT_XTP_SES_KEY_SZ
);
971 *key
= g_strdup_printf(XT_XTP_SES_KEY_HEX_FMT
,
972 rand_bytes
[0], rand_bytes
[1], rand_bytes
[2], rand_bytes
[3],
973 rand_bytes
[4], rand_bytes
[5], rand_bytes
[6], rand_bytes
[7]);
975 DNPRINTF(XT_D_DOWNLOAD
, "%s: new session key '%s'\n", __func__
, *key
);
979 xtp_generate_keys(void)
981 /* generate session keys for xtp pages */
982 generate_xtp_session_key(&dl_session_key
);
983 generate_xtp_session_key(&hl_session_key
);
984 generate_xtp_session_key(&cl_session_key
);
985 generate_xtp_session_key(&fl_session_key
);
986 generate_xtp_session_key(&ab_session_key
);
987 generate_xtp_session_key(&sv_session_key
);
991 * validate a xtp session key.
995 validate_xtp_session_key(struct tab
*t
, char *trusted
, char *untrusted
)
997 if (strcmp(trusted
, untrusted
) != 0) {
998 show_oops(t
, "%s: xtp session key mismatch possible spoof",
1007 * is the url xtp protocol? (xxxt://)
1008 * if so, parse and despatch correct bahvior
1011 parse_xtp_url(struct tab
*t
, const char *url
)
1013 char *dup
= NULL
, *p
, *last
= NULL
;
1014 uint8_t n_tokens
= 0;
1015 char *tokens
[4] = {NULL
, NULL
, NULL
, ""};
1016 struct xtp_despatch
*dsp
, *dsp_match
= NULL
;
1021 * tokens array meaning:
1023 * tokens[1] = session key
1024 * tokens[2] = action
1025 * tokens[3] = optional argument
1028 DNPRINTF(XT_D_URL
, "%s: url %s\n", __func__
, url
);
1030 if (strncmp(url
, XT_XTP_STR
, strlen(XT_XTP_STR
)))
1033 dup
= g_strdup(url
+ strlen(XT_XTP_STR
));
1035 /* split out the url */
1036 for ((p
= strtok_r(dup
, "/", &last
)); p
;
1037 (p
= strtok_r(NULL
, "/", &last
))) {
1039 tokens
[n_tokens
++] = p
;
1042 /* should be atleast three fields 'class/seskey/command/arg' */
1046 dsp
= xtp_despatches
;
1047 req_class
= atoi(tokens
[0]);
1048 while (dsp
->xtp_class
) {
1049 if (dsp
->xtp_class
== req_class
) {
1056 /* did we find one atall? */
1057 if (dsp_match
== NULL
) {
1058 show_oops(t
, "%s: no matching xtp despatch found", __func__
);
1062 /* check session key and call despatch function */
1063 if (validate_xtp_session_key(t
, *(dsp_match
->session_key
), tokens
[1])) {
1064 ret
= TRUE
; /* all is well, this was a valid xtp request */
1065 dsp_match
->handle_func(t
, atoi(tokens
[2]), atoi(tokens
[3]));
1076 * update all favorite tabs apart from one. Pass NULL if
1077 * you want to update all.
1080 update_favorite_tabs(struct tab
*apart_from
)
1083 if (!updating_fl_tabs
) {
1084 updating_fl_tabs
= 1; /* stop infinite recursion */
1085 TAILQ_FOREACH(t
, &tabs
, entry
)
1086 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_FL
)
1087 && (t
!= apart_from
))
1088 xtp_page_fl(t
, NULL
);
1089 updating_fl_tabs
= 0;
1094 * update all download tabs apart from one. Pass NULL if
1095 * you want to update all.
1098 update_download_tabs(struct tab
*apart_from
)
1101 if (!updating_dl_tabs
) {
1102 updating_dl_tabs
= 1; /* stop infinite recursion */
1103 TAILQ_FOREACH(t
, &tabs
, entry
)
1104 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_DL
)
1105 && (t
!= apart_from
))
1106 xtp_page_dl(t
, NULL
);
1107 updating_dl_tabs
= 0;
1112 * update all cookie tabs apart from one. Pass NULL if
1113 * you want to update all.
1116 update_cookie_tabs(struct tab
*apart_from
)
1119 if (!updating_cl_tabs
) {
1120 updating_cl_tabs
= 1; /* stop infinite recursion */
1121 TAILQ_FOREACH(t
, &tabs
, entry
)
1122 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_CL
)
1123 && (t
!= apart_from
))
1124 xtp_page_cl(t
, NULL
);
1125 updating_cl_tabs
= 0;
1130 * update all history tabs apart from one. Pass NULL if
1131 * you want to update all.
1134 update_history_tabs(struct tab
*apart_from
)
1138 if (!updating_hl_tabs
) {
1139 updating_hl_tabs
= 1; /* stop infinite recursion */
1140 TAILQ_FOREACH(t
, &tabs
, entry
)
1141 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_HL
)
1142 && (t
!= apart_from
))
1143 xtp_page_hl(t
, NULL
);
1144 updating_hl_tabs
= 0;
1149 * update all search tabs apart from one. Pass NULL if
1150 * you want to update all.
1153 update_search_tabs(struct tab
*apart_from
)
1157 if (!updating_sl_tabs
) {
1158 updating_sl_tabs
= 1; /* stop infinite recursion */
1159 TAILQ_FOREACH(t
, &tabs
, entry
)
1160 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_SL
)
1161 && (t
!= apart_from
))
1162 xtp_page_sl(t
, NULL
);
1163 updating_sl_tabs
= 0;
1168 * update all about tabs apart from one. Pass NULL if
1169 * you want to update all.
1172 update_about_tabs(struct tab
*apart_from
)
1176 if (!updating_ab_tabs
) {
1177 updating_ab_tabs
= 1; /* stop infinite recursion */
1178 TAILQ_FOREACH(t
, &tabs
, entry
)
1179 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_AB
)
1180 && (t
!= apart_from
))
1181 xtp_page_ab(t
, NULL
);
1182 updating_ab_tabs
= 0;
1187 * update all secviolation tabs apart from one. Pass NULL if
1188 * you want to update all.
1191 update_secviolation_tabs(struct tab
*apart_from
)
1195 if (!updating_sv_tabs
) {
1196 updating_sv_tabs
= 1; /* stop infinite recursion */
1197 TAILQ_FOREACH(t
, &tabs
, entry
)
1198 if ((t
->xtp_meaning
== XT_XTP_TAB_MEANING_SV
)
1199 && (t
!= apart_from
))
1200 xtp_page_sv(t
, NULL
);
1201 updating_sv_tabs
= 0;
1206 xtp_page_ab(struct tab
*t
, struct karg
*args
)
1211 show_oops(NULL
, "about invalid parameters");
1214 * Generate a new session key for next page instance.
1215 * This only happens for the top level call to xtp_page_ab()
1216 * in which case updating_sl_tabs is 0.
1218 if (!updating_ab_tabs
)
1219 generate_xtp_session_key(&ab_session_key
);
1221 body
= g_strdup_printf("<b>Version: %s</b>"
1222 #ifdef XOMBRERO_BUILDSTR
1223 "<br><b>Build: %s</b>"
1225 "<br><b>WebKit: %d.%d.%d</b>"
1226 "<br><b>User Agent: %d.%d</b>"
1227 #ifdef WEBKITGTK_API_VERSION
1228 "<br><b>WebKit API: %.1f</b>"
1230 "<br><b>Configuration: %s" PS
"<a href='%s%d/%s/%d'>%s</a>"
1231 " (remember to reload after any changes)</b>"
1235 "<li>Marco Peereboom <marco@peereboom.us></li>"
1236 "<li>Stevan Andjelkovic <stevan@student.chalmers.se></li>"
1237 "<li>Edd Barrett <vext01@gmail.com></li>"
1238 "<li>Todd T. Fries <todd@fries.net></li>"
1239 "<li>Raphael Graf <r@undefined.ch></li>"
1240 "<li>Michal Mazurek <akfaew@jasminek.net></li>"
1241 "<li>Josh Rickmar <jrick@devio.us></li>"
1243 "Copyrights and licenses can be found on the xombrero "
1244 "<a href=\"http://opensource.conformal.com/wiki/xombrero\">website</a>"
1246 #ifdef XOMBRERO_BUILDSTR
1247 version
, XOMBRERO_BUILDSTR
,
1251 WEBKIT_MAJOR_VERSION
, WEBKIT_MINOR_VERSION
, WEBKIT_MICRO_VERSION
,
1252 WEBKIT_USER_AGENT_MAJOR_VERSION
, WEBKIT_USER_AGENT_MINOR_VERSION
1253 #ifdef WEBKITGTK_API_VERSION
1254 ,WEBKITGTK_API_VERSION
1260 XT_XTP_AB_EDIT_CONF
,
1264 page
= get_html_page("About", body
, "", 0);
1267 load_webkit_string(t
, page
, XT_URI_ABOUT_ABOUT
);
1269 update_about_tabs(t
);
1276 /* show a list of favorites (bookmarks) */
1278 xtp_page_fl(struct tab
*t
, struct karg
*args
)
1280 char file
[PATH_MAX
];
1282 char *uri
= NULL
, *title
= NULL
;
1283 size_t len
, lineno
= 0;
1285 char *body
, *tmp
, *page
= NULL
;
1286 const char delim
[3] = {'\\', '\\', '\0'};
1288 DNPRINTF(XT_D_FAVORITE
, "%s:", __func__
);
1291 warn("%s: bad param", __func__
);
1293 /* new session key */
1294 if (!updating_fl_tabs
)
1295 generate_xtp_session_key(&fl_session_key
);
1297 /* open favorites */
1298 snprintf(file
, sizeof file
, "%s" PS
"%s", work_dir
, XT_FAVS_FILE
);
1299 if ((f
= fopen(file
, "r")) == NULL
) {
1300 show_oops(t
, "Can't open favorites file: %s", strerror(errno
));
1305 body
= g_strdup_printf("<table style='table-layout:fixed'><tr>"
1306 "<th style='width: 40px'>#</th><th>Link</th>"
1307 "<th style='width: 40px'>Rm</th></tr>\n");
1310 if ((title
= fparseln(f
, &len
, &lineno
, delim
, 0)) == NULL
)
1312 if (strlen(title
) == 0) {
1318 if ((uri
= fparseln(f
, &len
, &lineno
, delim
, 0)) == NULL
)
1319 if (feof(f
) || ferror(f
)) {
1320 show_oops(t
, "favorites file corrupt");
1326 body
= g_strdup_printf("%s<tr>"
1328 "<td><a href='%s'>%s</a></td>"
1329 "<td style='text-align: center'>"
1330 "<a href='%s%d/%s/%d/%d'>X</a></td>"
1332 body
, i
, uri
, title
,
1333 XT_XTP_STR
, XT_XTP_FL
, fl_session_key
, XT_XTP_FL_REMOVE
, i
);
1345 /* if none, say so */
1348 body
= g_strdup_printf("%s<tr>"
1349 "<td colspan='3' style='text-align: center'>"
1350 "No favorites - To add one use the 'favadd' command."
1351 "</td></tr>", body
);
1356 body
= g_strdup_printf("%s</table>", body
);
1366 page
= get_html_page("Favorites", body
, "", 1);
1367 load_webkit_string(t
, page
, XT_URI_ABOUT_FAVORITES
);
1371 update_favorite_tabs(t
);
1380 * Return a new string with a download row (in html)
1381 * appended. Old string is freed.
1384 xtp_page_dl_row(struct tab
*t
, char *html
, struct download
*dl
)
1387 WebKitDownloadStatus stat
;
1388 const gchar
*destination
;
1389 char *status_html
= NULL
, *cmd_html
= NULL
, *new_html
;
1391 char cur_sz
[FMT_SCALED_STRSIZE
];
1392 char tot_sz
[FMT_SCALED_STRSIZE
];
1395 DNPRINTF(XT_D_DOWNLOAD
, "%s: dl->id %d\n", __func__
, dl
->id
);
1397 /* All actions wil take this form:
1398 * xxxt://class/seskey
1400 xtp_prefix
= g_strdup_printf("%s%d/%s/",
1401 XT_XTP_STR
, XT_XTP_DL
, dl_session_key
);
1403 stat
= webkit_download_get_status(dl
->download
);
1406 case WEBKIT_DOWNLOAD_STATUS_FINISHED
:
1407 status_html
= g_strdup_printf("Finished");
1408 cmd_html
= g_strdup_printf(
1409 "<a href='%s%d/%d'>Remove</a> / <a href='%s%d/%d'>Unlink</a>",
1410 xtp_prefix
, XT_XTP_DL_REMOVE
, dl
->id
, xtp_prefix
,
1411 XT_XTP_DL_UNLINK
, dl
->id
);
1413 case WEBKIT_DOWNLOAD_STATUS_STARTED
:
1414 /* gather size info */
1415 progress
= 100 * webkit_download_get_progress(dl
->download
);
1418 webkit_download_get_current_size(dl
->download
), cur_sz
);
1420 webkit_download_get_total_size(dl
->download
), tot_sz
);
1422 status_html
= g_strdup_printf(
1423 "<div style='width: 100%%' align='center'>"
1424 "<div class='progress-outer'>"
1425 "<div class='progress-inner' style='width: %.2f%%'>"
1426 "</div></div></div>"
1427 "<div class='dlstatus'>%s of %s (%.2f%%)</div>",
1428 progress
, cur_sz
, tot_sz
, progress
);
1430 cmd_html
= g_strdup_printf("<a href='%s%d/%d'>Cancel</a>",
1431 xtp_prefix
, XT_XTP_DL_CANCEL
, dl
->id
);
1435 case WEBKIT_DOWNLOAD_STATUS_CANCELLED
:
1436 status_html
= g_strdup_printf("Cancelled");
1437 cmd_html
= g_strdup_printf(
1438 "<a href='%s%d/%d'>Restart</a> / <a href='%s%d/%d'>Remove</a> / <a href='%s%d/%d'>Unlink</a>",
1439 xtp_prefix
, XT_XTP_DL_START
, dl
->id
,
1440 xtp_prefix
, XT_XTP_DL_REMOVE
, dl
->id
, xtp_prefix
,
1441 XT_XTP_DL_UNLINK
, dl
->id
);
1443 case WEBKIT_DOWNLOAD_STATUS_ERROR
:
1444 status_html
= g_strdup_printf("Error!");
1445 cmd_html
= g_strdup_printf(
1446 "<a href='%s%d/%d'>Restart</a> / <a href='%s%d/%d'>Remove</a> / <a href='%s%d/%d'>Unlink</a>",
1447 xtp_prefix
, XT_XTP_DL_START
, dl
->id
,
1448 xtp_prefix
, XT_XTP_DL_REMOVE
, dl
->id
, xtp_prefix
,
1449 XT_XTP_DL_UNLINK
, dl
->id
);
1451 case WEBKIT_DOWNLOAD_STATUS_CREATED
:
1452 cmd_html
= g_strdup_printf("<a href='%s%d/%d'>Start</a> / <a href='%s%d/%d'>Cancel</a>",
1453 xtp_prefix
, XT_XTP_DL_START
, dl
->id
, xtp_prefix
,
1454 XT_XTP_DL_CANCEL
, dl
->id
);
1455 status_html
= g_strdup_printf("Created");
1458 show_oops(t
, "%s: unknown download status", __func__
);
1461 destination
= webkit_download_get_destination_uri(dl
->download
);
1462 /* we might not have a destination set yet */
1464 destination
= webkit_download_get_suggested_filename(dl
->download
);
1465 new_html
= g_strdup_printf(
1466 "%s\n<tr><td>%s</td><td>%s</td>"
1467 "<td style='text-align:center'>%s</td></tr>\n",
1468 html
, basename((char *)destination
),
1469 status_html
, cmd_html
);
1473 g_free(status_html
);
1483 /* cookie management XTP page */
1485 xtp_page_cl(struct tab
*t
, struct karg
*args
)
1487 char *body
, *page
, *tmp
;
1488 int i
= 1; /* all ids start 1 */
1490 GSList
*sc
, *pc
, *pc_start
;
1492 char *type
, *table_headers
, *last_domain
;
1494 DNPRINTF(XT_D_CMD
, "%s", __func__
);
1497 show_oops(NULL
, "%s invalid parameters", __func__
);
1501 /* Generate a new session key */
1502 if (!updating_cl_tabs
)
1503 generate_xtp_session_key(&cl_session_key
);
1506 table_headers
= g_strdup_printf("<table><tr>"
1509 "<th style='width:200px'>Value</th>"
1513 "<th>HTTP<br />only</th>"
1514 "<th style='width:40px'>Rm</th></tr>\n");
1516 sc
= soup_cookie_jar_all_cookies(s_cookiejar
);
1517 pc
= soup_cookie_jar_all_cookies(p_cookiejar
);
1520 body
= g_strdup_printf("<div align=\"center\"><a href=\"%s%d/%s/%d\">"
1521 "[ Remove All Cookies From All Domains ]</a></div>\n",
1522 XT_XTP_STR
, XT_XTP_CL
, cl_session_key
, XT_XTP_CL_REMOVE_ALL
);
1524 last_domain
= strdup("");
1525 for (; sc
; sc
= sc
->next
) {
1528 if (strcmp(last_domain
, c
->domain
) != 0) {
1532 last_domain
= strdup(c
->domain
);
1536 body
= g_strdup_printf("%s</table>"
1537 "<h2>%s</h2><div align=\"center\">"
1538 "<a href='%s%d/%s/%d/%d'>"
1539 "[ Remove All From This Domain ]"
1542 XT_XTP_STR
, XT_XTP_CL
, cl_session_key
,
1543 XT_XTP_CL_REMOVE_DOMAIN
, domain_id
,
1548 body
= g_strdup_printf("<h2>%s</h2>"
1549 "<div align=\"center\">"
1550 "<a href='%s%d/%s/%d/%d'>"
1551 "[ Remove All From This Domain ]</a></div>%s\n",
1552 c
->domain
, XT_XTP_STR
, XT_XTP_CL
,
1553 cl_session_key
, XT_XTP_CL_REMOVE_DOMAIN
,
1554 domain_id
, table_headers
);
1559 for (pc
= pc_start
; pc
; pc
= pc
->next
)
1560 if (soup_cookie_equal(pc
->data
, c
)) {
1561 type
= "Session + Persistent";
1566 body
= g_strdup_printf(
1569 "<td style='word-wrap:normal'>%s</td>"
1571 " <textarea rows='4'>%s</textarea>"
1577 "<td style='text-align:center'>"
1578 "<a href='%s%d/%s/%d/%d'>X</a></td></tr>\n",
1585 soup_date_to_string(c
->expires
, SOUP_DATE_COOKIE
) : "",
1600 soup_cookies_free(sc
);
1601 soup_cookies_free(pc
);
1603 /* small message if there are none */
1605 body
= g_strdup_printf("%s\n<tr><td style='text-align:center'"
1606 "colspan='8'>No Cookies</td></tr>\n", table_headers
);
1609 body
= g_strdup_printf("%s</table>", body
);
1612 page
= get_html_page("Cookie Jar", body
, "", TRUE
);
1614 g_free(table_headers
);
1615 g_free(last_domain
);
1617 load_webkit_string(t
, page
, XT_URI_ABOUT_COOKIEJAR
);
1618 update_cookie_tabs(t
);
1626 xtp_page_hl(struct tab
*t
, struct karg
*args
)
1628 char *body
, *page
, *tmp
;
1630 int i
= 1; /* all ids start 1 */
1632 DNPRINTF(XT_D_CMD
, "%s", __func__
);
1635 show_oops(NULL
, "%s invalid parameters", __func__
);
1639 /* Generate a new session key */
1640 if (!updating_hl_tabs
)
1641 generate_xtp_session_key(&hl_session_key
);
1644 body
= g_strdup_printf("<div align=\"center\"><a href=\"%s%d/%s/%d\">"
1645 "[ Remove All ]</a></div>"
1646 "<table style='table-layout:fixed'><tr>"
1647 "<th>URI</th><th>Title</th><th>Last visited</th>"
1648 "<th style='width: 40px'>Rm</th></tr>\n",
1649 XT_XTP_STR
, XT_XTP_HL
, hl_session_key
, XT_XTP_HL_REMOVE_ALL
);
1651 RB_FOREACH_REVERSE(h
, history_list
, &hl
) {
1653 body
= g_strdup_printf(
1655 "<td><a href='%s'>%s</a></td>"
1658 "<td style='text-align: center'>"
1659 "<a href='%s%d/%s/%d/%d'>X</a></td></tr>\n",
1660 body
, h
->uri
, h
->uri
, h
->title
, ctime(&h
->time
),
1661 XT_XTP_STR
, XT_XTP_HL
, hl_session_key
,
1662 XT_XTP_HL_REMOVE
, i
);
1668 /* small message if there are none */
1671 body
= g_strdup_printf("%s\n<tr><td style='text-align:center'"
1672 "colspan='4'>No History</td></tr>\n", body
);
1677 body
= g_strdup_printf("%s</table>", body
);
1680 page
= get_html_page("History", body
, "", TRUE
);
1684 * update all history manager tabs as the xtp session
1685 * key has now changed. No need to update the current tab.
1686 * Already did that above.
1688 update_history_tabs(t
);
1690 load_webkit_string(t
, page
, XT_URI_ABOUT_HISTORY
);
1697 * Generate a web page detailing the status of any downloads
1700 xtp_page_dl(struct tab
*t
, struct karg
*args
)
1702 struct download
*dl
;
1703 char *body
, *page
, *tmp
;
1707 DNPRINTF(XT_D_DOWNLOAD
, "%s", __func__
);
1710 show_oops(NULL
, "%s invalid parameters", __func__
);
1715 * Generate a new session key for next page instance.
1716 * This only happens for the top level call to xtp_page_dl()
1717 * in which case updating_dl_tabs is 0.
1719 if (!updating_dl_tabs
)
1720 generate_xtp_session_key(&dl_session_key
);
1722 /* header - with refresh so as to update */
1723 if (refresh_interval
>= 1)
1724 ref
= g_strdup_printf(
1725 "<meta http-equiv='refresh' content='%u"
1726 ";url=%s%d/%s/%d' />\n",
1735 body
= g_strdup_printf("<div align='center'>"
1736 "<p>\n<a href='%s%d/%s/%d'>\n[ Refresh Downloads ]</a>\n"
1737 "</p><table><tr><th style='width: 60%%'>"
1738 "File</th>\n<th>Progress</th><th>Command</th></tr>\n",
1739 XT_XTP_STR
, XT_XTP_DL
, dl_session_key
, XT_XTP_DL_LIST
);
1741 RB_FOREACH_REVERSE(dl
, download_list
, &downloads
) {
1742 body
= xtp_page_dl_row(t
, body
, dl
);
1746 /* message if no downloads in list */
1749 body
= g_strdup_printf("%s\n<tr><td colspan='3'"
1750 " style='text-align: center'>"
1751 "No downloads</td></tr>\n", body
);
1756 body
= g_strdup_printf("%s</table></div>", body
);
1759 page
= get_html_page("Downloads", body
, ref
, 1);
1764 * update all download manager tabs as the xtp session
1765 * key has now changed. No need to update the current tab.
1766 * Already did that above.
1768 update_download_tabs(t
);
1770 load_webkit_string(t
, page
, XT_URI_ABOUT_DOWNLOADS
);
1777 xtp_page_sl(struct tab
*t
, struct karg
*args
)
1780 char *page
, *body
, *tmp
;
1782 DNPRINTF(XT_D_SEARCH
, "%s", __func__
);
1785 * Generate a new session key for next page instance.
1786 * This only happens for the top level call to xtp_page_sl()
1787 * in which case updating_sl_tabs is 0.
1789 if (!updating_sl_tabs
)
1790 generate_xtp_session_key(&sl_session_key
);
1793 show_oops(NULL
, "%s invalid parameters", __func__
);
1797 body
= g_strdup_printf("<p>The xombrero authors will not choose a "
1798 "default search engine for you. What follows is a list of search "
1799 "engines (in no particular order) you may be interested in. "
1800 "To permanently choose a search engine, click [ Select ] to save "
1801 "<tt>search_string</tt> as a runtime setting, or set "
1802 "<tt>search_string</tt> to the appropriate URL in your xombrero "
1803 "configuration.</p>");
1806 body
= g_strdup_printf("%s\n<table style='table-layout:fixed'><tr>"
1807 "<th style='width: 200px'>Name</th><th>URL</th>"
1808 "<th style='width: 100px'>Select</th></tr>\n", body
);
1811 for (i
= 0; i
< (sizeof search_list
/ sizeof (struct search_type
)); ++i
)
1812 body
= search_engine_add(body
, search_list
[i
].name
,
1813 search_list
[i
].url
, i
);
1816 body
= g_strdup_printf("%s</table>", body
);
1819 page
= get_html_page("Choose a search engine", body
, "", 1);
1823 * update all search tabs as the xtp session key has now changed. No
1824 * need to update the current tab. Already did that above.
1826 update_search_tabs(t
);
1828 load_webkit_string(t
, page
, XT_URI_ABOUT_SEARCH
);
1835 xtp_page_sv(struct tab
*t
, struct karg
*args
)
1839 struct secviolation find
, *sv
;
1843 show_oops(NULL
, "secviolation invalid parameters");
1845 /* Generate a new session key for next page instance.
1846 * This only happens for the top level call to xtp_page_ab()
1847 * in which case updating_sv_tabs = 0.
1849 if (!updating_sv_tabs
)
1850 generate_xtp_session_key(&sv_session_key
);
1853 find
.xtp_arg
= t
->xtp_arg
;
1854 sv
= RB_FIND(secviolation_list
, &svl
, &find
);
1858 sv
= g_malloc(sizeof(struct secviolation
));
1859 sv
->xtp_arg
= ++arg
;
1863 RB_INSERT(secviolation_list
, &svl
, sv
);
1866 if (sv
->uri
== NULL
|| (soupuri
= soup_uri_new(sv
->uri
)) == NULL
)
1869 body
= g_strdup_printf(
1870 "The domain of the page you have tried to access, %s, has a "
1871 "different remote certificate then the local cached version from a "
1872 "previous visit. As a security precaution to help prevent against "
1873 "man-in-the-middle attacks, please choose one of the following "
1874 "actions to continue, or disable the <tt>warn_cert_changes</tt> "
1875 "setting in your xombrero configuration."
1876 "<p><b>Choose an action:"
1877 "<br><a href='%s%d/%s/%d/%d'>Show Certificate</a>"
1878 "<br><a href='%s%d/%s/%d/%d'>Allow for this Session</a>"
1879 "<br><a href='%s%d/%s/%d/%d'>Cache new certificate</a>",
1881 XT_XTP_STR
, XT_XTP_SV
, sv_session_key
, XT_XTP_SV_SHOW_CERT
,
1883 XT_XTP_STR
, XT_XTP_SV
, sv_session_key
, XT_XTP_SV_ALLOW_SESSION
,
1885 XT_XTP_STR
, XT_XTP_SV
, sv_session_key
, XT_XTP_SV_CACHE
,
1888 page
= get_html_page("Security Violation", body
, "", 0);
1891 update_secviolation_tabs(t
);
1893 load_webkit_string(t
, page
, XT_URI_ABOUT_SECVIOLATION
);
1897 soup_uri_free(soupuri
);
1903 startpage(struct tab
*t
, struct karg
*args
)
1905 char *page
, *body
, *b
;
1909 show_oops(NULL
, "startpage invalid parameters");
1911 body
= g_strdup_printf("<b>Startup Exception(s):</b><p>");
1913 TAILQ_FOREACH(s
, &spl
, entry
) {
1915 body
= g_strdup_printf("%s%s<br>", body
, s
->line
);
1919 page
= get_html_page("Startup Exception", body
, "", 0);
1922 load_webkit_string(t
, page
, XT_URI_ABOUT_STARTPAGE
);
1929 startpage_add(const char *fmt
, ...)
1939 if (vasprintf(&msg
, fmt
, ap
) == -1)
1940 errx(1, "startpage_add failed");
1943 s
= g_malloc0(sizeof *s
);
1946 TAILQ_INSERT_TAIL(&spl
, s
, entry
);
1950 show_g_object_settings(GObject
*o
, char *str
, int recurse
)
1952 char *b
, *body
, *valstr
;
1959 const gchar
*string
;
1968 GParamSpec
**proplist
;
1969 char *tmpstr
, *tmpsettings
;
1971 if (!G_IS_OBJECT(o
)) {
1972 fprintf(stderr
, "%s is not a g_object\n", str
);
1973 return g_strdup("");
1975 proplist
= g_object_class_list_properties(
1976 G_OBJECT_GET_CLASS(o
), &n_props
);
1977 body
= g_strdup_printf("%s: %3d settings\n", str
, n_props
);
1978 for (i
=0; i
< n_props
; i
++) {
1979 pspec
= proplist
[i
];
1980 tname
= G_OBJECT_TYPE_NAME(pspec
);
1981 bzero(&value
, sizeof value
);
1984 if (!(pspec
->flags
& G_PARAM_READABLE
))
1985 valstr
= g_strdup_printf("not a readable property");
1987 g_value_init(&value
, G_PARAM_SPEC_VALUE_TYPE(pspec
));
1988 g_object_get_property(G_OBJECT(o
), pspec
->name
,
1992 /* based on the type, recurse and display values */
1993 if (valstr
== NULL
) {
1994 typeno
= G_TYPE_FUNDAMENTAL( G_VALUE_TYPE(&value
) );
1997 number
= g_value_get_enum(&value
);
1998 valstr
= g_strdup_printf("%d", number
);
2001 number
= g_value_get_int(&value
);
2002 valstr
= g_strdup_printf("%d", number
);
2005 number64
= (int64_t)g_value_get_int64(&value
);
2006 valstr
= g_strdup_printf("%" PRIo64
, number64
);
2009 unumber
= g_value_get_uint(&value
);
2010 valstr
= g_strdup_printf("%d", unumber
);
2014 (uint64_t)g_value_get_uint64(&value
);
2016 g_strdup_printf("%" PRIu64
, unumber64
);
2019 unumber
= g_value_get_flags(&value
);
2020 valstr
= g_strdup_printf("0x%x", unumber
);
2022 case G_TYPE_BOOLEAN
:
2023 boolean
= g_value_get_boolean(&value
);
2024 valstr
= g_strdup_printf("%s",
2025 boolean
? "TRUE" : "FALSE");
2028 fp
= g_value_get_float(&value
);
2029 valstr
= g_strdup_printf("%f", fp
);
2032 fpd
= g_value_get_double(&value
);
2033 valstr
= g_strdup_printf("%f", fpd
);
2036 string
= g_value_get_string(&value
);
2037 valstr
= g_strdup_printf("\"%s\"",
2041 object
= g_value_get_object(&value
);
2042 if (object
!= NULL
) {
2044 tmpstr
= g_strdup_printf("%s ",
2046 tmpsettings
= show_g_object_settings(
2047 object
, tmpstr
, recurse
);
2048 valstr
= g_strdup_printf(
2052 g_free(tmpsettings
);
2054 valstr
= g_strdup_printf("<...>");
2057 valstr
= g_strdup_printf("NULL");
2061 valstr
= g_strdup_printf(
2062 "type %s unhandled",
2068 body
= g_strdup_printf(
2069 "%s%s: %3d: flags=0x%08x, %-13s %s = %s\n",
2070 body
, str
, i
, pspec
->flags
, tname
, pspec
->name
,
2080 about_webkit(struct tab
*t
, struct karg
*arg
)
2082 char *page
, *body
, *settingstr
;
2084 settingstr
= show_g_object_settings(G_OBJECT(t
->settings
),
2086 body
= g_strdup_printf("<pre>%s</pre>\n", settingstr
);
2089 page
= get_html_page("About Webkit", body
, "", 0);
2092 load_webkit_string(t
, page
, XT_URI_ABOUT_WEBKIT
);
2099 allthethings(struct tab
*t
, struct karg
*arg
)
2101 char *page
, *body
, *b
, *settingstr
;
2102 extern GtkWidget
*main_window
;
2104 body
= show_g_object_settings(G_OBJECT(t
->wv
), "t->wv", 1);
2106 settingstr
= show_g_object_settings(G_OBJECT(t
->inspector
),
2108 body
= g_strdup_printf("%s%s", body
, settingstr
);
2112 settingstr
= show_g_object_settings(G_OBJECT(main_window
),
2114 body
= g_strdup_printf("%s%s", body
, settingstr
);
2118 body
= g_strdup_printf("<pre>%scan paste clipboard = %d\n</pre>", body
,
2119 webkit_web_view_can_paste_clipboard(t
->wv
));
2122 page
= get_html_page("About All The Things _o/", body
, "", 0);
2125 load_webkit_string(t
, page
, XT_URI_ABOUT_ALLTHETHINGS
);