"Fossies" - the Fresh Open Source Software Archive 
Member "xombrero-1.6.4/about.c" (17 Feb 2015, 54697 Bytes) of package /linux/www/old/xombrero-1.6.4.tgz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "about.c" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
1.6.3_vs_1.6.4.
1 /*
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>
9 *
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.
13 *
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.
21 */
22
23 #include <xombrero.h>
24
25 /*
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
31 *
32 * Don't begin xtp class/actions as 0. atoi returns that on error.
33 *
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.
36 */
37
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" \
52 ".progress-outer{" \
53 "border: 1px solid black;" \
54 " height: 8px;" \
55 " width: 90%%}\n" \
56 ".progress-inner{float: left;" \
57 " height: 8px;" \
58 " background: green}\n" \
59 ".dlstatus{font-size: small;" \
60 " text-align: center}\n" \
61 "table#settings{background-color: #eee;"\
62 " border: 0px;" \
63 " margin: 15px;}\n" \
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" \
74 "</style>\n"
75
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 *);
87
88 /*
89 * If you change the index of any of these, correct the
90 * XT_XTP_TAB_MEANING_* macros in xombrero.h!
91 */
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 },
114 };
115
116 struct search_type {
117 const char *name;
118 const char *url;
119 } search_list[] = {
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" },
128 };
129
130 /*
131 * Session IDs.
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)
134 */
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
138
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;
147
148 size_t
149 about_list_size(void)
150 {
151 return (LENGTH(about_list));
152 }
153
154 gchar *
155 get_html_page(gchar *title, gchar *body, gchar *head, bool addstyles)
156 {
157 gchar *r;
158
159 r = g_strdup_printf(XT_DOCTYPE XT_HTML_TAG
160 "<head>\n"
161 "<title>%s</title>\n"
162 "%s"
163 "%s"
164 "</head>\n"
165 "<body>\n"
166 "<h1>%s</h1>\n"
167 "%s\n</body>\n"
168 "</html>",
169 title,
170 addstyles ? XT_PAGE_STYLE : "",
171 head,
172 title,
173 body);
174
175 return (r);
176 }
177
178 /*
179 * Display a web page from a HTML string in memory, rather than from a URL
180 */
181 void
182 load_webkit_string(struct tab *t, const char *str, gchar *title, int nohist)
183 {
184 char file[PATH_MAX];
185 int i;
186
187 if (g_signal_handler_is_connected(t->wv, t->progress_handle))
188 g_signal_handler_disconnect(t->wv, t->progress_handle);
189
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);
193 if (t->item)
194 g_object_ref(t->item);
195 }
196
197 t->xtp_meaning = XT_XTP_TAB_MEANING_NORMAL;
198 if (title) {
199 /* set t->xtp_meaning */
200 for (i = 0; i < LENGTH(about_list); i++)
201 if (!strcmp(title, about_list[i].name)) {
202 t->xtp_meaning = i;
203 break;
204 }
205
206 webkit_web_view_load_string(t->wv, str, NULL, encoding,
207 XT_XTP_STR);
208 #if GTK_CHECK_VERSION(2, 20, 0)
209 gtk_spinner_stop(GTK_SPINNER(t->spinner));
210 gtk_widget_hide(t->spinner);
211 #endif
212 snprintf(file, sizeof file, "%s" PS "%s", resource_dir, icons[0]);
213 xt_icon_from_file(t, file);
214 }
215
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;
220 }
221
222 t->progress_handle = g_signal_connect(t->wv,
223 "notify::progress", G_CALLBACK(webview_progress_changed_cb), t);
224 }
225
226 int
227 blank(struct tab *t, struct karg *args)
228 {
229 if (t == NULL)
230 show_oops(NULL, "blank invalid parameters");
231
232 load_webkit_string(t, "", XT_URI_ABOUT_BLANK, 0);
233
234 return (0);
235 }
236
237 int
238 help(struct tab *t, struct karg *args)
239 {
240 char *page, *head, *body;
241
242 if (t == NULL)
243 show_oops(NULL, "help invalid parameters");
244
245 head = "<meta http-equiv=\"REFRESH\" content=\"0;"
246 "url=https://opensource.conformal.com/cgi-bin/man-cgi?xombrero\">"
247 "</head>\n";
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>";
251
252 page = get_html_page(XT_NAME, body, head, FALSE);
253
254 load_webkit_string(t, page, XT_URI_ABOUT_HELP, 0);
255 g_free(page);
256
257 return (0);
258 }
259
260 int
261 stats(struct tab *t, struct karg *args)
262 {
263 char *page, *body, *s, line[64 * 1024];
264 uint64_t line_count = 0;
265 FILE *r_cookie_f;
266
267 if (t == NULL)
268 show_oops(NULL, "stats invalid parameters");
269
270 line[0] = '\0';
271 if (save_rejected_cookies) {
272 if ((r_cookie_f = fopen(rc_fname, "r"))) {
273 for (;;) {
274 s = fgets(line, sizeof line, r_cookie_f);
275 if (s == NULL || feof(r_cookie_f) ||
276 ferror(r_cookie_f))
277 break;
278 line_count++;
279 }
280 fclose(r_cookie_f);
281 snprintf(line, sizeof line,
282 "<br/>Cookies blocked(*) total: %" PRIu64,
283 line_count);
284 } else
285 show_oops(t, "Can't open blocked cookies file: %s",
286 strerror(errno));
287 }
288
289 body = g_strdup_printf(
290 "Cookies blocked(*) this session: %" PRIu64
291 "%s"
292 "<p><small><b>*</b> results vary based on settings</small></p>",
293 blocked_cookies,
294 line);
295
296 page = get_html_page("Statistics", body, "", 0);
297 g_free(body);
298
299 load_webkit_string(t, page, XT_URI_ABOUT_STATS, 0);
300 g_free(page);
301
302 return (0);
303 }
304
305 void
306 show_certs(struct tab *t, gnutls_x509_crt_t *certs,
307 size_t cert_count, char *title)
308 {
309 gnutls_datum_t *cinfo;
310 char *tmp, *body;
311 int i;
312
313 body = g_strdup("");
314
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,
318 cinfo)) {
319 gnutls_free(cinfo);
320 g_free(body);
321 return;
322 }
323
324 tmp = body;
325 body = g_strdup_printf("%s<h2>Cert #%d</h2><pre>%s</pre>",
326 body, i, cinfo->data);
327 gnutls_free(cinfo);
328 g_free(tmp);
329 }
330
331 tmp = get_html_page(title, body, "", 0);
332 g_free(body);
333
334 load_webkit_string(t, tmp, XT_URI_ABOUT_CERTS, 0);
335 g_free(tmp);
336 }
337
338 int
339 ca_cmd(struct tab *t, struct karg *args)
340 {
341 FILE *f = NULL;
342 int rv = 1, certs_read;
343 unsigned int certs = 0;
344 struct stat sb;
345 gnutls_datum_t dt;
346 gnutls_x509_crt_t *c = NULL;
347 char *certs_buf = NULL, *s;
348
349 if ((f = fopen(ssl_ca_file, "r")) == NULL) {
350 show_oops(t, "Can't open CA file: %s", ssl_ca_file);
351 return (1);
352 }
353
354 if (fstat(fileno(f), &sb) == -1) {
355 show_oops(t, "Can't stat CA file: %s", ssl_ca_file);
356 goto done;
357 }
358
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));
362 goto done;
363 }
364 certs_buf[sb.st_size] = '\0';
365
366 s = certs_buf;
367 while ((s = strstr(s, "BEGIN CERTIFICATE"))) {
368 certs++;
369 s += strlen("BEGIN CERTIFICATE");
370 }
371
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");
380 goto done;
381 }
382 show_certs(t, c, certs_read, "Certificate Authority Certificates");
383 done:
384 if (c)
385 gnutls_free(c);
386 if (certs_buf)
387 g_free(certs_buf);
388 if (f)
389 fclose(f);
390
391 return (rv);
392 }
393
394 int
395 cookie_show_wl(struct tab *t, struct karg *args)
396 {
397 args->i = XT_SHOW | XT_WL_PERSISTENT | XT_WL_SESSION;
398 wl_show(t, args, "Cookie White List", &c_wl);
399
400 return (0);
401 }
402
403 int
404 js_show_wl(struct tab *t, struct karg *args)
405 {
406 args->i = XT_SHOW | XT_WL_PERSISTENT | XT_WL_SESSION;
407 wl_show(t, args, "JavaScript White List", &js_wl);
408
409 return (0);
410 }
411
412 int
413 cookie_cmd(struct tab *t, struct karg *args)
414 {
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;
419 toggle_cwl(t, args);
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) {
424 remove_cookie_all();
425 update_cookie_tabs(NULL);
426 }
427
428 return (0);
429 }
430
431 int
432 js_cmd(struct tab *t, struct karg *args)
433 {
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;
441 toggle_js(t, args);
442 } else if (args->i & XT_DELETE)
443 show_oops(t, "'js delete' currently unimplemented");
444
445 return (0);
446 }
447
448 int
449 pl_show_wl(struct tab *t, struct karg *args)
450 {
451 args->i = XT_SHOW | XT_WL_PERSISTENT | XT_WL_SESSION;
452 wl_show(t, args, "Plugin White List", &pl_wl);
453
454 return (0);
455 }
456
457 int
458 pl_cmd(struct tab *t, struct karg *args)
459 {
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;
467 toggle_pl(t, args);
468 } else if (args->i & XT_DELETE)
469 show_oops(t, "'plugin delete' currently unimplemented");
470
471 return (0);
472 }
473
474 int
475 https_show_wl(struct tab *t, struct karg *args)
476 {
477 args->i = XT_SHOW | XT_WL_PERSISTENT | XT_WL_SESSION;
478 wl_show(t, args, "HTTPS Force List", &force_https);
479
480 return (0);
481 }
482
483 int
484 https_cmd(struct tab *t, struct karg *args)
485 {
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");
496
497 return (0);
498 }
499
500 /*
501 * cancel, remove, etc. downloads
502 */
503 void
504 xtp_handle_dl(struct tab *t, uint8_t cmd, int id, const char *query)
505 {
506 struct download find, *d = NULL;
507 #ifndef __MINGW32__
508 char *file = NULL;
509 const char *uri = NULL;
510 #endif
511
512 DNPRINTF(XT_D_DOWNLOAD, "download control: cmd %d, id %d\n", cmd, id);
513
514 /* some commands require a valid download id */
515 if (cmd != XT_XTP_DL_LIST) {
516 /* lookup download in question */
517 find.id = id;
518 d = RB_FIND(download_list, &downloads, &find);
519
520 if (d == NULL) {
521 show_oops(t, "%s: no such download", __func__);
522 return;
523 }
524 }
525
526 /* decide what to do */
527 switch (cmd) {
528 case XT_XTP_DL_START:
529 /* our downloads always needs to be
530 * restarted if called from here
531 */
532 download_start(t, d, XT_DL_RESTART);
533 break;
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);
538 break;
539 case XT_XTP_DL_UNLINK:
540 #ifdef __MINGW32__
541 /* XXX uri's aren't handled properly on windows? */
542 unlink(webkit_download_get_destination_uri(d->download));
543 #else
544 uri = webkit_download_get_destination_uri(d->download);
545 if ((file = g_filename_from_uri(uri, NULL, NULL)) != NULL) {
546 unlink(file);
547 g_free(file);
548 }
549 #endif
550 /* FALLTHROUGH */
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);
555 break;
556 case XT_XTP_DL_LIST:
557 /* Nothing */
558 break;
559 default:
560 show_oops(t, "%s: unknown command", __func__);
561 break;
562 };
563 xtp_page_dl(t, NULL);
564 }
565
566 void
567 xtp_handle_hl(struct tab *t, uint8_t cmd, int id, const char *query)
568 {
569 struct history *h, *next, *ht;
570 int i = 1;
571
572 switch (cmd) {
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);
577 if (id == i) {
578 RB_REMOVE(history_list, &hl, h);
579 g_free((gpointer) h->title);
580 g_free((gpointer) h->uri);
581 g_free(h);
582 break;
583 }
584 i++;
585 }
586 break;
587 case XT_XTP_HL_REMOVE_ALL:
588 RB_FOREACH_SAFE(h, history_list, &hl, ht)
589 RB_REMOVE(history_list, &hl, h);
590 break;
591 case XT_XTP_HL_LIST:
592 /* Nothing - just xtp_page_hl() below */
593 break;
594 default:
595 show_oops(t, "%s: unknown command", __func__);
596 break;
597 };
598
599 xtp_page_hl(t, NULL);
600 }
601
602 /* remove a favorite */
603 void
604 remove_favorite(struct tab *t, int index)
605 {
606 char file[PATH_MAX], *title, *uri = NULL;
607 char *new_favs, *tmp;
608 FILE *f;
609 int i;
610 size_t len, lineno;
611
612 /* open favorites */
613 snprintf(file, sizeof file, "%s" PS "%s", work_dir, XT_FAVS_FILE);
614
615 if ((f = fopen(file, "r")) == NULL) {
616 show_oops(t, "%s: can't open favorites: %s",
617 __func__, strerror(errno));
618 return;
619 }
620
621 /* build a string which will become the new favorites file */
622 new_favs = g_strdup("");
623
624 for (i = 1;;) {
625 if ((title = fparseln(f, &len, &lineno, NULL, 0)) == NULL)
626 if (feof(f) || ferror(f))
627 break;
628 /* XXX THIS IS NOT THE RIGHT HEURISTIC */
629 if (len == 0) {
630 free(title);
631 title = NULL;
632 continue;
633 }
634
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));
639 goto clean;
640 }
641 }
642
643 /* as long as this isn't the one we are deleting add to file */
644 if (i != index) {
645 tmp = new_favs;
646 new_favs = g_strdup_printf("%s%s\n%s\n",
647 new_favs, title, uri);
648 g_free(tmp);
649 }
650
651 free(uri);
652 uri = NULL;
653 free(title);
654 title = NULL;
655 i++;
656 }
657 fclose(f);
658
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));
663 goto clean;
664 }
665
666 if (fwrite(new_favs, strlen(new_favs), 1, f) != 1)
667 show_oops(t, "%s: can't fwrite", __func__);
668 fclose(f);
669
670 clean:
671 if (uri)
672 free(uri);
673 if (title)
674 free(title);
675
676 g_free(new_favs);
677 }
678
679 int
680 add_favorite(struct tab *t, struct karg *args)
681 {
682 char file[PATH_MAX];
683 FILE *f;
684 char *line = NULL;
685 size_t urilen, linelen;
686 gchar *argtitle = NULL;
687 const gchar *uri, *title;
688
689 if (t == NULL)
690 return (1);
691
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__);
695 return (1);
696 }
697
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));
701 return (1);
702 }
703
704 if (args->s && strlen(g_strstrip(args->s)))
705 argtitle = html_escape(g_strstrip(args->s));
706
707 title = argtitle ? argtitle : get_title(t, FALSE);
708 uri = get_uri(t);
709
710 if (title == NULL || uri == NULL) {
711 show_oops(t, "can't add page to favorites");
712 goto done;
713 }
714
715 urilen = strlen(uri);
716
717 for (;;) {
718 if ((line = fparseln(f, &linelen, NULL, NULL, 0)) == NULL) {
719 if (feof(f))
720 break;
721 else {
722 show_oops(t, "Error reading favorites file: %s",
723 strerror(errno));
724 goto done;
725 }
726 }
727
728 if (linelen == urilen && !strcmp(line, uri))
729 goto done;
730
731 free(line);
732 line = NULL;
733 }
734
735 fprintf(f, "\n%s\n%s", title, uri);
736 done:
737 if (argtitle)
738 g_free(argtitle);
739 if (line)
740 free(line);
741 fclose(f);
742
743 update_favorite_tabs(NULL);
744
745 return (0);
746 }
747
748 char *
749 search_engine_add(char *body, const char *name, const char *url,
750 const char *key, int select)
751 {
752 char *b = body;
753
754 body = g_strdup_printf("%s<tr>"
755 "<td>%s</td>"
756 "<td>%s</td>"
757 "<td style='text-align: center'>"
758 "<a href='%s%d/%s/%d/%d'>[ Select ]</a></td>"
759 "</tr>\n",
760 body,
761 name,
762 url,
763 XT_XTP_STR, XT_XTP_SL, key, XT_XTP_SL_SET, select);
764 g_free(b);
765 return (body);
766 }
767
768 void
769 xtp_handle_ab(struct tab *t, uint8_t cmd, int arg, const char *query)
770 {
771 char config[PATH_MAX];
772 char *cmdstr;
773 char **sv;
774
775 switch (cmd) {
776 case XT_XTP_AB_EDIT_CONF:
777 if (external_editor == NULL || strlen(external_editor) == 0) {
778 show_oops(t, "external_editor is unset");
779 break;
780 }
781
782 snprintf(config, sizeof config, "%s" PS ".%s", pwd->pw_dir,
783 XT_CONF_FILE);
784 sv = g_strsplit(external_editor, "<file>", -1);
785 cmdstr = g_strjoinv(config, sv);
786 g_strfreev(sv);
787 sv = g_strsplit_set(cmdstr, " \t", -1);
788
789 if (!g_spawn_async(NULL, sv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
790 NULL, NULL))
791 show_oops(t, "%s: could not spawn process", __func__);
792
793 g_strfreev(sv);
794 g_free(cmdstr);
795 break;
796 default:
797 show_oops(t, "%s, invalid about command", __func__);
798 break;
799 };
800 xtp_page_ab(t, NULL);
801 }
802 void
803 xtp_handle_fl(struct tab *t, uint8_t cmd, int arg, const char *query)
804 {
805 struct karg args = {0};
806
807 switch (cmd) {
808 case XT_XTP_FL_LIST:
809 /* nothing, just the below call to xtp_page_fl() */
810 break;
811 case XT_XTP_FL_REMOVE:
812 remove_favorite(t, arg);
813 args.i = XT_DELETE;
814 break;
815 default:
816 show_oops(t, "%s: invalid favorites command", __func__);
817 break;
818 };
819
820 xtp_page_fl(t, &args);
821 }
822
823 void
824 xtp_handle_cl(struct tab *t, uint8_t cmd, int arg, const char *query)
825 {
826 switch (cmd) {
827 case XT_XTP_CL_LIST:
828 /* nothing, just xtp_page_cl() */
829 break;
830 case XT_XTP_CL_REMOVE:
831 remove_cookie(arg);
832 break;
833 case XT_XTP_CL_REMOVE_DOMAIN:
834 remove_cookie_domain(arg);
835 break;
836 case XT_XTP_CL_REMOVE_ALL:
837 remove_cookie_all();
838 break;
839 default:
840 show_oops(t, "%s: unknown cookie xtp command", __func__);
841 break;
842 };
843
844 xtp_page_cl(t, NULL);
845 }
846
847 void
848 xtp_handle_sl(struct tab *t, uint8_t cmd, int arg, const char *query)
849 {
850 const char *search;
851 char *enc_search, *uri;
852 char **sv;
853
854 switch (cmd) {
855 case XT_XTP_SL_SET:
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");
859 break;
860 default:
861 show_oops(t, "%s: unknown search xtp command", __func__);
862 break;
863 };
864
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);
869 load_uri(t, uri);
870 g_free(enc_search);
871 g_strfreev(sv);
872 g_free(uri);
873 }
874
875 void
876 xtp_handle_sv(struct tab *t, uint8_t cmd, int id, const char *query)
877 {
878 SoupURI *soupuri = NULL;
879 struct karg args = {0};
880 struct secviolation find, *sv;
881
882 find.xtp_arg = id;
883 if ((sv = RB_FIND(secviolation_list, &svl, &find)) == NULL)
884 return;
885
886 args.ptr = (void *)sv->t;
887 args.s = sv->uri;
888
889 switch (cmd) {
890 case XT_XTP_SV_SHOW_NEW_CERT:
891 args.i = XT_SHOW;
892 if (cert_cmd(t, &args)) {
893 xtp_page_sv(t, &args);
894 return;
895 }
896 break;
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);
901 return;
902 }
903 break;
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);
908 focus_webview(t);
909 break;
910 case XT_XTP_SV_CACHE:
911 args.i = XT_CACHE;
912 if (cert_cmd(t, &args)) {
913 xtp_page_sv(t, &args);
914 return;
915 }
916 load_uri(t, sv->uri);
917 focus_webview(t);
918 break;
919 default:
920 show_oops(t, "%s: invalid secviolation command", __func__);
921 break;
922 };
923
924 g_free(sv->uri);
925 if (soupuri)
926 soup_uri_free(soupuri);
927 RB_REMOVE(secviolation_list, &svl, sv);
928 }
929
930 void
931 xtp_handle_rt(struct tab *t, uint8_t cmd, int id, const char *query)
932 {
933 struct set_reject *sr;
934 GHashTable *new_settings = NULL;
935 int modify;
936 char *val, *curval, *s;
937 int i = 0;
938
939 switch (cmd) {
940 case XT_XTP_RT_SAVE:
941 if (query == NULL)
942 break;
943 new_settings = soup_form_decode(query);
944 for (i = 0; i < get_settings_size(); ++i) {
945 if (!rs[i].activate)
946 continue;
947 val = (char *)g_hash_table_lookup(new_settings,
948 rs[i].name);
949 modify = 0;
950 switch (rs[i].type) {
951 case XT_S_INT: /* FALLTHROUGH */
952 case XT_S_BOOL:
953 if (atoi(val) != *rs[i].ival)
954 modify = 1;
955 break;
956 case XT_S_DOUBLE:
957 if (atof(val) < (*rs[i].dval - 0.0001) ||
958 atof(val) > (*rs[i].dval + 0.0001))
959 modify = 1;
960 break;
961 case XT_S_STR:
962 s = (rs[i].sval == NULL || *rs[i].sval == NULL)
963 ? "" : *rs[i].sval;
964 if (rs[i].sval && g_strcmp0(val, s))
965 modify = 1;
966 else if (rs[i].s && rs[i].s->get) {
967 curval = rs[i].s->get(NULL);
968 if (g_strcmp0(val, curval))
969 modify = 1;
970 g_free(curval);
971 }
972 break;
973 case XT_S_INVALID: /* FALLTHROUGH */
974 default:
975 break;
976 }
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);
982 continue;
983 }
984 if (modify)
985 if (save_runtime_setting(rs[i].name, val))
986 show_oops(t, "error");
987 }
988 break;
989 default:
990 show_oops(t, "%s: invalid set command", __func__);
991 break;
992 }
993
994 if (new_settings)
995 g_hash_table_destroy(new_settings);
996
997 xtp_page_rt(t, NULL);
998 }
999
1000 /* link an XTP class to it's session key and handler function */
1001 struct xtp_despatch {
1002 uint8_t xtp_class;
1003 void (*handle_func)(struct tab *, uint8_t, int,
1004 const char *query);
1005 };
1006
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 }
1017 };
1018
1019 /*
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.
1023 */
1024 void
1025 generate_xtp_session_key(char **key)
1026 {
1027 uint8_t rand_bytes[XT_XTP_SES_KEY_SZ];
1028
1029 if (key == NULL)
1030 return;
1031
1032 /* free old key */
1033 if (*key != NULL)
1034 g_free(*key);
1035
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]);
1041
1042 DNPRINTF(XT_D_DOWNLOAD, "%s: new session key '%s'\n", __func__, *key);
1043 }
1044
1045 /*
1046 * validate a xtp session key.
1047 * return (1) if OK
1048 */
1049 int
1050 validate_xtp_session_key(struct tab *t, char *key)
1051 {
1052 if (t == NULL || t->session_key == NULL || key == NULL)
1053 return (0);
1054
1055 if (strcmp(t->session_key, key) != 0) {
1056 show_oops(t, "%s: xtp session key mismatch possible spoof",
1057 __func__);
1058 return (0);
1059 }
1060
1061 return (1);
1062 }
1063
1064 /*
1065 * is the url xtp protocol? (xxxt://)
1066 * if so, parse and despatch correct bahvior
1067 */
1068 int
1069 parse_xtp_url(struct tab *t, const char *uri_str)
1070 {
1071 SoupURI *uri = NULL;
1072 struct xtp_despatch *dsp, *dsp_match = NULL;
1073 int ret = FALSE;
1074 int class = 0;
1075 char **sv = NULL;
1076
1077 /*
1078 * uri->host = class
1079 * sv[0] = session key
1080 * sv[1] = command
1081 * sv[2] = optional argument
1082 */
1083
1084 DNPRINTF(XT_D_URL, "%s: url %s\n", __func__, uri_str);
1085
1086 if ((uri = soup_uri_new(uri_str)) == NULL)
1087 goto clean;
1088 if (strncmp(uri->scheme, XT_XTP_SCHEME, strlen(XT_XTP_SCHEME)))
1089 goto clean;
1090 if (uri->host == NULL || strlen(uri->host) == 0)
1091 goto clean;
1092 if ((sv = g_strsplit(uri->path + 1, "/", 3)) == NULL)
1093 goto clean;
1094
1095 if (sv[0] == NULL || sv[1] == NULL)
1096 goto clean;
1097
1098 dsp = xtp_despatches;
1099 class = atoi(uri->host);
1100 while (dsp->xtp_class) {
1101 if (dsp->xtp_class == class) {
1102 dsp_match = dsp;
1103 break;
1104 }
1105 dsp++;
1106 }
1107
1108 /* did we find one atall? */
1109 if (dsp_match == NULL) {
1110 show_oops(t, "%s: no matching xtp despatch found", __func__);
1111 goto clean;
1112 }
1113
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 */
1117 if (sv[2])
1118 dsp_match->handle_func(t, atoi(sv[1]), atoi(sv[2]),
1119 uri->query);
1120 else
1121 dsp_match->handle_func(t, atoi(sv[1]), 0, uri->query);
1122 }
1123
1124 clean:
1125 if (uri)
1126 soup_uri_free(uri);
1127 if (sv)
1128 g_strfreev(sv);
1129
1130 return (ret);
1131 }
1132
1133 /*
1134 * update all favorite tabs apart from one. Pass NULL if
1135 * you want to update all.
1136 */
1137 void
1138 update_favorite_tabs(struct tab *apart_from)
1139 {
1140 struct tab *t;
1141
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;
1149 }
1150 }
1151
1152 /*
1153 * update all download tabs apart from one. Pass NULL if
1154 * you want to update all.
1155 */
1156 void
1157 update_download_tabs(struct tab *apart_from)
1158 {
1159 struct tab *t;
1160
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;
1168 }
1169 }
1170
1171 /*
1172 * update all cookie tabs apart from one. Pass NULL if
1173 * you want to update all.
1174 */
1175 void
1176 update_cookie_tabs(struct tab *apart_from)
1177 {
1178 struct tab *t;
1179
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;
1187 }
1188 }
1189
1190 /*
1191 * update all history tabs apart from one. Pass NULL if
1192 * you want to update all.
1193 */
1194 void
1195 update_history_tabs(struct tab *apart_from)
1196 {
1197 struct tab *t;
1198
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;
1206 }
1207 }
1208
1209 /*
1210 * update all search tabs apart from one. Pass NULL if
1211 * you want to update all.
1212 */
1213 void
1214 update_search_tabs(struct tab *apart_from)
1215 {
1216 struct tab *t;
1217
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;
1225 }
1226 }
1227
1228 int
1229 xtp_page_ab(struct tab *t, struct karg *args)
1230 {
1231 char *page, *body;
1232
1233 if (t == NULL) {
1234 show_oops(NULL, "about invalid parameters");
1235 return (-1);
1236 }
1237
1238 generate_xtp_session_key(&t->session_key);
1239
1240 body = g_strdup_printf("<b>Version: %s</b>"
1241 #ifdef XOMBRERO_BUILDSTR
1242 "<br><b>Build: %s</b>"
1243 #endif
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>"
1248 #endif
1249 "<br><b>Configuration: %s" PS "<a href='%s%d/%s/%d'>.%s</a>"
1250 " (remember to restart the browser after any changes)</b>"
1251 "<p>"
1252 "Authors:"
1253 "<ul>"
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>"
1262 "</ul>"
1263 "Copyrights and licenses can be found on the xombrero "
1264 "<a href=\"https://opensource.conformal.com/wiki/xombrero\">website</a>"
1265 "</p>",
1266 #ifdef XOMBRERO_BUILDSTR
1267 version, XOMBRERO_BUILDSTR,
1268 #else
1269 version,
1270 #endif
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
1275 #endif
1276 ,pwd->pw_dir,
1277 XT_XTP_STR,
1278 XT_XTP_AB,
1279 t->session_key ? t->session_key : "",
1280 XT_XTP_AB_EDIT_CONF,
1281 XT_CONF_FILE
1282 );
1283
1284 page = get_html_page("About", body, "", 0);
1285 g_free(body);
1286
1287 load_webkit_string(t, page, XT_URI_ABOUT_ABOUT, 0);
1288
1289 g_free(page);
1290
1291 return (0);
1292 }
1293
1294 /* show a list of favorites (bookmarks) */
1295 int
1296 xtp_page_fl(struct tab *t, struct karg *args)
1297 {
1298 char file[PATH_MAX];
1299 FILE *f;
1300 char *uri = NULL, *title = NULL;
1301 size_t len, lineno = 0;
1302 int i, failed = 0;
1303 char *body, *tmp, *page = NULL;
1304 const char delim[3] = {'\\', '\\', '\0'};
1305
1306 DNPRINTF(XT_D_FAVORITE, "%s:", __func__);
1307
1308 if (t == NULL) {
1309 show_oops(NULL, "%s: bad param", __func__);
1310 return (-1);
1311 }
1312
1313 generate_xtp_session_key(&t->session_key);
1314
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));
1319 return (1);
1320 }
1321
1322 /* body */
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");
1327 else
1328 body = g_strdup_printf("<table style='table-layout:fixed'><tr>"
1329 "<th style='width: 40px'>#</th><th>Link</th></tr>\n");
1330
1331 for (i = 1;;) {
1332 if ((title = fparseln(f, &len, &lineno, delim, 0)) == NULL)
1333 break;
1334 if (strlen(title) == 0) {
1335 free(title);
1336 title = NULL;
1337 continue;
1338 }
1339
1340 if ((uri = fparseln(f, &len, &lineno, delim, 0)) == NULL)
1341 if (feof(f) || ferror(f)) {
1342 show_oops(t, "favorites file corrupt");
1343 failed = 1;
1344 break;
1345 }
1346
1347 tmp = body;
1348 if (args && args->i & XT_DELETE)
1349 body = g_strdup_printf("%s<tr>"
1350 "<td>%d</td>"
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>"
1354 "</tr>\n",
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);
1359 else
1360 body = g_strdup_printf("%s<tr>"
1361 "<td>%d</td>"
1362 "<td><a href='%s'>%s</a></td>"
1363 "</tr>\n",
1364 body, i, uri, title);
1365 g_free(tmp);
1366
1367 free(uri);
1368 uri = NULL;
1369 free(title);
1370 title = NULL;
1371 i++;
1372 }
1373 fclose(f);
1374
1375 /* if none, say so */
1376 if (i == 1) {
1377 tmp = body;
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);
1382 g_free(tmp);
1383 }
1384
1385 tmp = body;
1386 body = g_strdup_printf("%s</table>", body);
1387 g_free(tmp);
1388
1389 if (uri)
1390 free(uri);
1391 if (title)
1392 free(title);
1393
1394 /* render */
1395 if (!failed) {
1396 page = get_html_page("Favorites", body, "", 1);
1397 load_webkit_string(t, page, XT_URI_ABOUT_FAVORITES, 0);
1398 g_free(page);
1399 }
1400
1401 update_favorite_tabs(t);
1402
1403 if (body)
1404 g_free(body);
1405
1406 return (failed);
1407 }
1408
1409 /*
1410 * Return a new string with a download row (in html)
1411 * appended. Old string is freed.
1412 */
1413 char *
1414 xtp_page_dl_row(struct tab *t, char *html, struct download *dl)
1415 {
1416
1417 WebKitDownloadStatus stat;
1418 const gchar *destination;
1419 gchar *d;
1420 char *status_html = NULL, *cmd_html = NULL, *new_html;
1421 gdouble progress;
1422 char cur_sz[FMT_SCALED_STRSIZE];
1423 char tot_sz[FMT_SCALED_STRSIZE];
1424 char *xtp_prefix;
1425
1426 DNPRINTF(XT_D_DOWNLOAD, "%s: dl->id %d\n", __func__, dl->id);
1427
1428 /* All actions wil take this form:
1429 * xxxt://class/seskey
1430 */
1431 xtp_prefix = g_strdup_printf("%s%d/%s/",
1432 XT_XTP_STR, XT_XTP_DL, t->session_key);
1433
1434 stat = webkit_download_get_status(dl->download);
1435
1436 switch (stat) {
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);
1443 break;
1444 case WEBKIT_DOWNLOAD_STATUS_STARTED:
1445 /* gather size info */
1446 progress = 100 * webkit_download_get_progress(dl->download);
1447
1448 fmt_scaled(
1449 webkit_download_get_current_size(dl->download), cur_sz);
1450 fmt_scaled(
1451 webkit_download_get_total_size(dl->download), tot_sz);
1452
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);
1460
1461 cmd_html = g_strdup_printf("<a href='%s%d/%d'>Cancel</a>",
1462 xtp_prefix, XT_XTP_DL_CANCEL, dl->id);
1463
1464 break;
1465 /* LLL */
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);
1473 break;
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);
1481 break;
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");
1487 break;
1488 default:
1489 show_oops(t, "%s: unknown download status", __func__);
1490 };
1491
1492 destination = webkit_download_get_destination_uri(dl->download);
1493 /* we might not have a destination set yet */
1494 if (!destination)
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);
1501 g_free(d);
1502 g_free(html);
1503
1504 if (status_html)
1505 g_free(status_html);
1506
1507 if (cmd_html)
1508 g_free(cmd_html);
1509
1510 g_free(xtp_prefix);
1511
1512 return new_html;
1513 }
1514
1515 /* cookie management XTP page */
1516 int
1517 xtp_page_cl(struct tab *t, struct karg *args)
1518 {
1519 char *body, *page, *tmp;
1520 int i = 1; /* all ids start 1 */
1521 int domain_id = 0;
1522 GSList *sc, *pc, *pc_start;
1523 SoupCookie *c;
1524 char *type, *table_headers, *last_domain;
1525
1526 DNPRINTF(XT_D_CMD, "%s", __func__);
1527
1528 if (t == NULL) {
1529 show_oops(NULL, "%s invalid parameters", __func__);
1530 return (1);
1531 }
1532
1533 generate_xtp_session_key(&t->session_key);
1534
1535 /* table headers */
1536 table_headers = g_strdup_printf("<table><tr>"
1537 "<th>Type</th>"
1538 "<th>Name</th>"
1539 "<th style='width:200px'>Value</th>"
1540 "<th>Path</th>"
1541 "<th>Expires</th>"
1542 "<th>Secure</th>"
1543 "<th>HTTP<br />only</th>"
1544 "<th style='width:40px'>Rm</th></tr>\n");
1545
1546 sc = soup_cookie_jar_all_cookies(s_cookiejar);
1547 pc = soup_cookie_jar_all_cookies(p_cookiejar);
1548 pc_start = pc;
1549
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);
1553
1554 last_domain = g_strdup("");
1555 for (; sc; sc = sc->next) {
1556 c = sc->data;
1557
1558 if (strcmp(last_domain, c->domain) != 0) {
1559 /* new domain */
1560 domain_id ++;
1561 g_free(last_domain);
1562 last_domain = g_strdup(c->domain);
1563
1564 if (body != NULL) {
1565 tmp = body;
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 ]"
1570 "</a></div>%s\n",
1571 body, c->domain,
1572 XT_XTP_STR, XT_XTP_CL, t->session_key,
1573 XT_XTP_CL_REMOVE_DOMAIN, domain_id,
1574 table_headers);
1575 g_free(tmp);
1576 } else {
1577 /* first domain */
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);
1585 }
1586 }
1587
1588 type = "Session";
1589 for (pc = pc_start; pc; pc = pc->next)
1590 if (soup_cookie_equal(pc->data, c)) {
1591 type = "Session + Persistent";
1592 break;
1593 }
1594
1595 tmp = body;
1596 body = g_strdup_printf(
1597 "%s\n<tr>"
1598 "<td>%s</td>"
1599 "<td style='word-wrap:normal'>%s</td>"
1600 "<td>"
1601 " <textarea rows='4'>%s</textarea>"
1602 "</td>"
1603 "<td>%s</td>"
1604 "<td>%s</td>"
1605 "<td>%d</td>"
1606 "<td>%d</td>"
1607 "<td style='text-align:center'>"
1608 "<a href='%s%d/%s/%d/%d'>X</a></td></tr>\n",
1609 body,
1610 type,
1611 c->name,
1612 c->value,
1613 c->path,
1614 c->expires ?
1615 soup_date_to_string(c->expires, SOUP_DATE_COOKIE) : "",
1616 c->secure,
1617 c->http_only,
1618
1619 XT_XTP_STR,
1620 XT_XTP_CL,
1621 t->session_key,
1622 XT_XTP_CL_REMOVE,
1623 i
1624 );
1625
1626 g_free(tmp);
1627 i++;
1628 }
1629
1630 soup_cookies_free(sc);
1631 soup_cookies_free(pc);
1632
1633 /* small message if there are none */
1634 if (i == 1) {
1635 body = g_strdup_printf("%s\n<tr><td style='text-align:center'"
1636 "colspan='8'>No Cookies</td></tr>\n", table_headers);
1637 }
1638 tmp = body;
1639 body = g_strdup_printf("%s</table>", body);
1640 g_free(tmp);
1641
1642 page = get_html_page("Cookie Jar", body, "", TRUE);
1643 g_free(body);
1644 g_free(table_headers);
1645 g_free(last_domain);
1646
1647 load_webkit_string(t, page, XT_URI_ABOUT_COOKIEJAR, 0);
1648 update_cookie_tabs(t);
1649
1650 g_free(page);
1651
1652 return (0);
1653 }
1654
1655 int
1656 xtp_page_hl(struct tab *t, struct karg *args)
1657 {
1658 char *body, *page, *tmp;
1659 struct history *h;
1660 int i = 1; /* all ids start 1 */
1661
1662 DNPRINTF(XT_D_CMD, "%s", __func__);
1663
1664 if (t == NULL) {
1665 show_oops(NULL, "%s invalid parameters", __func__);
1666 return (1);
1667 }
1668
1669 generate_xtp_session_key(&t->session_key);
1670
1671 /* body */
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);
1678
1679 RB_FOREACH_REVERSE(h, history_list, &hl) {
1680 tmp = body;
1681 body = g_strdup_printf(
1682 "%s\n<tr>"
1683 "<td><a href='%s'>%s</a></td>"
1684 "<td>%s</td>"
1685 "<td>%s</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);
1691
1692 g_free(tmp);
1693 i++;
1694 }
1695
1696 /* small message if there are none */
1697 if (i == 1) {
1698 tmp = body;
1699 body = g_strdup_printf("%s\n<tr><td style='text-align:center'"
1700 "colspan='4'>No History</td></tr>\n", body);
1701 g_free(tmp);
1702 }
1703
1704 tmp = body;
1705 body = g_strdup_printf("%s</table>", body);
1706 g_free(tmp);
1707
1708 page = get_html_page("History", body, "", TRUE);
1709 g_free(body);
1710
1711 /*
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.
1715 */
1716 update_history_tabs(t);
1717
1718 load_webkit_string(t, page, XT_URI_ABOUT_HISTORY, 0);
1719 g_free(page);
1720
1721 return (0);
1722 }
1723
1724 /*
1725 * Generate a web page detailing the status of any downloads
1726 */
1727 int
1728 xtp_page_dl(struct tab *t, struct karg *args)
1729 {
1730 struct download *dl;
1731 char *body, *page, *tmp;
1732 char *ref;
1733 int n_dl = 1;
1734
1735 DNPRINTF(XT_D_DOWNLOAD, "%s", __func__);
1736
1737 if (t == NULL) {
1738 show_oops(NULL, "%s invalid parameters", __func__);
1739 return (1);
1740 }
1741
1742 generate_xtp_session_key(&t->session_key);
1743
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",
1749 refresh_interval,
1750 XT_XTP_STR,
1751 XT_XTP_DL,
1752 t->session_key,
1753 XT_XTP_DL_LIST);
1754 else
1755 ref = g_strdup("");
1756
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);
1762
1763 RB_FOREACH_REVERSE(dl, download_list, &downloads) {
1764 body = xtp_page_dl_row(t, body, dl);
1765 n_dl++;
1766 }
1767
1768 /* message if no downloads in list */
1769 if (n_dl == 1) {
1770 tmp = body;
1771 body = g_strdup_printf("%s\n<tr><td colspan='3'"
1772 " style='text-align: center'>"
1773 "No downloads</td></tr>\n", body);
1774 g_free(tmp);
1775 }
1776
1777 tmp = body;
1778 body = g_strdup_printf("%s</table></div>", body);
1779 g_free(tmp);
1780
1781 page = get_html_page("Downloads", body, ref, 1);
1782 g_free(ref);
1783 g_free(body);
1784
1785 /*
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.
1789 */
1790 update_download_tabs(t);
1791
1792 load_webkit_string(t, page, XT_URI_ABOUT_DOWNLOADS, 0);
1793 g_free(page);
1794
1795 return (0);
1796 }
1797
1798 int
1799 xtp_page_sl(struct tab *t, struct karg *args)
1800 {
1801 int i;
1802 char *page, *body, *tmp;
1803
1804 DNPRINTF(XT_D_SEARCH, "%s", __func__);
1805
1806 generate_xtp_session_key(&t->session_key);
1807
1808 if (t == NULL) {
1809 show_oops(NULL, "%s invalid parameters", __func__);
1810 return (1);
1811 }
1812
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>");
1820
1821 tmp = body;
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);
1825 g_free(tmp);
1826
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);
1830
1831 tmp = body;
1832 body = g_strdup_printf("%s</table>", body);
1833 g_free(tmp);
1834
1835 page = get_html_page("Choose a search engine", body, "", 1);
1836 g_free(body);
1837
1838 /*
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.
1841 */
1842 update_search_tabs(t);
1843
1844 load_webkit_string(t, page, XT_URI_ABOUT_SEARCH, 0);
1845 g_free(page);
1846
1847 return (0);
1848 }
1849
1850 int
1851 xtp_page_sv(struct tab *t, struct karg *args)
1852 {
1853 SoupURI *soupuri;
1854 static int arg = 0;
1855 struct secviolation find, *sv;
1856 char *page, *body;
1857
1858 if (t == NULL) {
1859 show_oops(NULL, "secviolation invalid parameters");
1860 return (-1);
1861 }
1862
1863 generate_xtp_session_key(&t->session_key);
1864
1865 if (args == NULL) {
1866 find.xtp_arg = t->xtp_arg;
1867 sv = RB_FIND(secviolation_list, &svl, &find);
1868 if (sv == NULL)
1869 return (-1);
1870 } else {
1871 sv = g_malloc(sizeof(struct secviolation));
1872 sv->xtp_arg = ++arg;
1873 t->xtp_arg = arg;
1874 sv->t = t;
1875 sv->uri = args->s;
1876 RB_INSERT(secviolation_list, &svl, sv);
1877 }
1878
1879 if (sv->uri == NULL || (soupuri = soup_uri_new(sv->uri)) == NULL)
1880 return (-1);
1881
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 "
1891 "configuration."
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>",
1897 sv->uri,
1898 soupuri->host,
1899 XT_XTP_STR, XT_XTP_SV, t->session_key, XT_XTP_SV_ALLOW_SESSION,
1900 sv->xtp_arg,
1901 XT_XTP_STR, XT_XTP_SV, t->session_key, XT_XTP_SV_CACHE,
1902 sv->xtp_arg,
1903 XT_XTP_STR, XT_XTP_SV, t->session_key, XT_XTP_SV_SHOW_CACHED_CERT,
1904 sv->xtp_arg,
1905 XT_XTP_STR, XT_XTP_SV, t->session_key, XT_XTP_SV_SHOW_NEW_CERT,
1906 sv->xtp_arg);
1907
1908 page = get_html_page("Security Violation", body, "", 0);
1909 g_free(body);
1910
1911 load_webkit_string(t, page, XT_URI_ABOUT_SECVIOLATION, 1);
1912
1913 g_free(page);
1914 if (soupuri)
1915 soup_uri_free(soupuri);
1916
1917 return (0);
1918 }
1919
1920 int
1921 startpage(struct tab *t, struct karg *args)
1922 {
1923 char *page, *body, *b;
1924 struct sp *s;
1925
1926 if (t == NULL)
1927 show_oops(NULL, "startpage invalid parameters");
1928
1929 body = g_strdup_printf("<b>Startup Exception(s):</b><p>");
1930
1931 TAILQ_FOREACH(s, &spl, entry) {
1932 b = body;
1933 body = g_strdup_printf("%s%s<br>", body, s->line);
1934 g_free(b);
1935 }
1936
1937 page = get_html_page("Startup Exception", body, "", 0);
1938 g_free(body);
1939
1940 load_webkit_string(t, page, XT_URI_ABOUT_STARTPAGE, 0);
1941 g_free(page);
1942
1943 return (0);
1944 }
1945
1946 void
1947 startpage_add(const char *fmt, ...)
1948 {
1949 va_list ap;
1950 char *msg;
1951 struct sp *s;
1952
1953 if (fmt == NULL)
1954 return;
1955
1956 va_start(ap, fmt);
1957 if ((msg = g_strdup_vprintf(fmt, ap)) == NULL)
1958 errx(1, "startpage_add failed");
1959 va_end(ap);
1960
1961 s = g_malloc0(sizeof *s);
1962 s->line = msg;
1963
1964 TAILQ_INSERT_TAIL(&spl, s, entry);
1965 }
1966 gchar *show_g_object_settings(GObject *, char *, int);
1967
1968 char *
1969 xt_g_object_serialize(GValue *value, const gchar *tname, char *str, int recurse)
1970 {
1971 int typeno = 0;
1972 char *valstr, *tmpstr, *tmpsettings;
1973 GObject *object;
1974
1975 typeno = G_TYPE_FUNDAMENTAL( G_VALUE_TYPE(value) );
1976 switch ( typeno ) {
1977 case G_TYPE_ENUM:
1978 valstr = g_strdup_printf("%d",
1979 g_value_get_enum(value));
1980 break;
1981 case G_TYPE_CHAR:
1982 valstr = g_strdup_printf("%c",
1983 #if GLIB_CHECK_VERSION(2, 32, 0)
1984 g_value_get_schar(value));
1985 #else
1986 g_value_get_char(value));
1987 #endif
1988 break;
1989 case G_TYPE_UCHAR:
1990 valstr = g_strdup_printf("%c",
1991 g_value_get_uchar(value));
1992 break;
1993 case G_TYPE_LONG:
1994 valstr = g_strdup_printf("%ld",
1995 g_value_get_long(value));
1996 break;
1997 case G_TYPE_ULONG:
1998 valstr = g_strdup_printf("%ld",
1999 g_value_get_ulong(value));
2000 break;
2001 case G_TYPE_INT:
2002 valstr = g_strdup_printf("%d",
2003 g_value_get_int(value));
2004 break;
2005 case G_TYPE_INT64:
2006 valstr = g_strdup_printf("%" PRIo64,
2007 (int64_t) g_value_get_int64(value));
2008 break;
2009 case G_TYPE_UINT:
2010 valstr = g_strdup_printf("%d",
2011 g_value_get_uint(value));
2012 break;
2013 case G_TYPE_UINT64:
2014 valstr = g_strdup_printf("%" PRIu64,
2015 (uint64_t) g_value_get_uint64(value));
2016 break;
2017 case G_TYPE_FLAGS:
2018 valstr = g_strdup_printf("0x%x",
2019 g_value_get_flags(value));
2020 break;
2021 case G_TYPE_BOOLEAN:
2022 valstr = g_strdup_printf("%s",
2023 g_value_get_boolean(value) ? "TRUE" : "FALSE");
2024 break;
2025 case G_TYPE_FLOAT:
2026 valstr = g_strdup_printf("%f",
2027 g_value_get_float(value));
2028 break;
2029 case G_TYPE_DOUBLE:
2030 valstr = g_strdup_printf("%f",
2031 g_value_get_double(value));
2032 break;
2033 case G_TYPE_STRING:
2034 valstr = g_strdup_printf("\"%s\"",
2035 g_value_get_string(value));
2036 break;
2037 case G_TYPE_POINTER:
2038 valstr = g_strdup_printf("%p",
2039 g_value_get_pointer(value));
2040 break;
2041 case G_TYPE_OBJECT:
2042 object = g_value_get_object(value);
2043 if (object != NULL) {
2044 if (recurse) {
2045 tmpstr = g_strdup_printf("%s ", str);
2046 tmpsettings = show_g_object_settings( object,
2047 tmpstr, recurse);
2048 g_free(tmpstr);
2049
2050 if (strrchr(tmpsettings, '\n') != NULL) {
2051 valstr = g_strdup_printf("%s%s }",
2052 tmpsettings, str);
2053 g_free(tmpsettings);
2054 } else {
2055 valstr = tmpsettings;
2056 }
2057 } else {
2058 valstr = g_strdup_printf("<...>");
2059 }
2060 } else {
2061 valstr = g_strdup_printf("settings[] = NULL");
2062 }
2063 break;
2064 default:
2065 valstr = g_strdup_printf("type %s unhandled", tname);
2066 }
2067 return valstr;
2068 }
2069
2070 gchar *
2071 show_g_object_settings(GObject *o, char *str, int recurse)
2072 {
2073 char *b, *p, *body, *valstr, *tmpstr;
2074 guint n_props = 0;
2075 int i, typeno = 0;
2076 GParamSpec *pspec;
2077 const gchar *tname;
2078 GValue value;
2079 GParamSpec **proplist;
2080 const gchar *name;
2081
2082 if (!G_IS_OBJECT(o)) {
2083 fprintf(stderr, "%s is not a g_object\n", str);
2084 return g_strdup("");
2085 }
2086 proplist = g_object_class_list_properties(
2087 G_OBJECT_GET_CLASS(o), &n_props);
2088
2089 if (GTK_IS_WIDGET(o)) {
2090 name = gtk_widget_get_name(GTK_WIDGET(o));
2091 } else {
2092 name = "settings";
2093 }
2094 if (n_props == 0) {
2095 body = g_strdup_printf("%s[0] = { }", name);
2096 goto end_show_g_objects;
2097 }
2098
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);
2104 valstr = NULL;
2105
2106 if (!(pspec->flags & G_PARAM_READABLE))
2107 valstr = g_strdup_printf("not a readable property");
2108 else {
2109 g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
2110 g_object_get_property(G_OBJECT(o), pspec->name,
2111 &value);
2112 typeno = G_TYPE_FUNDAMENTAL( G_VALUE_TYPE(&value) );
2113 }
2114
2115 /* based on the type, recurse and display values */
2116 if (valstr == NULL) {
2117 valstr = xt_g_object_serialize(&value, tname, str,
2118 recurse);
2119 }
2120
2121 tmpstr = g_strdup_printf("%-13s %s%s%s,", tname, pspec->name,
2122 (typeno == G_TYPE_OBJECT) ? "." : " = ", valstr);
2123 b = body;
2124
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);
2131 } else {
2132 char *fmt;
2133 int strspaces;
2134 if (p == NULL)
2135 strspaces = XT_G_OBJECT_SPACING;
2136 else
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);
2140 g_free(fmt);
2141 }
2142 g_free(tmpstr);
2143 g_free(b);
2144 g_free(valstr);
2145 }
2146 end_show_g_objects:
2147 g_free(proplist);
2148 return (body);
2149 }
2150
2151 char *
2152 xt_append_settings(char *str, GObject *object, char *name, int recurse)
2153 {
2154 char *newstr, *settings;
2155
2156 settings = show_g_object_settings(object, name, recurse);
2157 if (str == NULL)
2158 str = g_strdup("");
2159
2160 newstr = g_strdup_printf("%s%s %s%s };\n", str, name, settings, name);
2161 g_free(str);
2162
2163 return newstr;
2164 }
2165
2166 int
2167 about_webkit(struct tab *t, struct karg *arg)
2168 {
2169 char *page, *body, *settingstr;
2170
2171 settingstr = xt_append_settings(NULL, G_OBJECT(t->settings),
2172 "t->settings", 0);
2173 body = g_strdup_printf("<pre>%s</pre>\n", settingstr);
2174 g_free(settingstr);
2175
2176 page = get_html_page("About Webkit", body, "", 0);
2177 g_free(body);
2178
2179 load_webkit_string(t, page, XT_URI_ABOUT_WEBKIT, 0);
2180 g_free(page);
2181
2182 return (0);
2183 }
2184
2185 static int toplevelcount = 0;
2186
2187 void
2188 xt_append_toplevel(GtkWindow *w, char **body)
2189 {
2190 char *n;
2191
2192 n = g_strdup_printf("toplevel#%d", toplevelcount++);
2193 *body = xt_append_settings(*body, G_OBJECT(w), n, 0);
2194 g_free(n);
2195 }
2196
2197 int
2198 allthethings(struct tab *t, struct karg *arg)
2199 {
2200 GList *list;
2201 char *page, *body, *b;
2202
2203 body = xt_append_settings(NULL, G_OBJECT(t->wv), "t->wv", 1);
2204 body = xt_append_settings(body, G_OBJECT(t->inspector),
2205 "t->inspector", 1);
2206 #if 0 /* not until warnings are gone */
2207 body = xt_append_settings(body, G_OBJECT(session),
2208 "session", 1);
2209 #endif
2210 toplevelcount = 0;
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);
2215 g_list_free(list);
2216
2217 b = body;
2218 body = g_strdup_printf("<pre>%scan paste clipboard = %d\n</pre>", body,
2219 webkit_web_view_can_paste_clipboard(t->wv));
2220 g_free(b);
2221
2222 page = get_html_page("About All The Things _o/", body, "", 0);
2223 g_free(body);
2224
2225 load_webkit_string(t, page, XT_URI_ABOUT_ALLTHETHINGS, 0);
2226 g_free(page);
2227
2228 return (0);
2229 }