include libgen.h for basename
[elinks.git] / src / dialogs / document.c
bloba401f001de9298e0f8aa0f0df471dcf91e49b18b
1 /* Information about current document and current link */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #ifdef HAVE_TIME_H
11 #include <time.h>
12 #endif
14 #include "elinks.h"
16 #include "bfu/dialog.h"
17 #include "cache/cache.h"
18 #include "dialogs/document.h"
19 #include "document/document.h"
20 #include "document/view.h"
21 #include "globhist/globhist.h"
22 #include "intl/gettext/libintl.h"
23 #include "protocol/header.h"
24 #include "protocol/uri.h"
25 #include "session/location.h"
26 #include "session/session.h"
27 #include "terminal/terminal.h"
28 #include "terminal/window.h"
29 #include "util/conv.h"
30 #include "util/memory.h"
31 #include "util/string.h"
32 #include "viewer/text/link.h"
33 #include "viewer/text/view.h"
35 void
36 nowhere_box(struct terminal *term, unsigned char *title)
38 assert(term);
39 if_assert_failed return;
41 if (!title || !*title)
42 title = N_("Info");
44 info_box(term, 0, title, ALIGN_CENTER,
45 N_("You are nowhere!"));
48 static void
49 add_link_info_to_string(struct string *msg, struct session *ses)
51 struct document_view *doc_view = current_frame(ses);
52 struct terminal *term = ses->tab->term;
53 unsigned char *a;
54 struct link *link;
56 if (!doc_view) return;
58 add_char_to_string(msg, '\n');
60 a = get_current_link_info(ses, doc_view);
61 if (a) {
62 add_format_to_string(msg, "\n%s: %s",
63 _("Link", term), a);
64 mem_free(a);
67 a = get_current_link_title(doc_view);
68 if (a) {
69 add_format_to_string(msg, "\n%s: %s",
70 _("Link title", term), a);
71 mem_free(a);
74 link = get_current_link_in_view(doc_view);
75 if (link) {
76 struct string img;
77 #ifdef CONFIG_GLOBHIST
78 struct global_history_item *historyitem;
79 #endif
81 if (link->where_img && init_string(&img)) {
82 add_string_uri_to_string(&img, link->where_img,
83 URI_PUBLIC);
84 decode_uri_string_for_display(&img);
86 add_format_to_string(msg, "\n%s: %s",
87 _("Link image", term),
88 img.source);
89 done_string(&img);
92 #ifdef CONFIG_GLOBHIST
93 historyitem = get_global_history_item(link->where);
94 if (historyitem) {
95 unsigned char *last_visit;
97 last_visit = ctime(&historyitem->last_visit);
99 if (last_visit)
100 add_format_to_string(msg,
101 "\n%s: %.24s",
102 _("Link last visit time",
103 term),
104 last_visit);
106 if (*historyitem->title)
107 add_format_to_string(msg, "\n%s: %s",
108 _("Link title (from history)",
109 term),
110 historyitem->title);
112 #endif
116 /* Link info message box. */
117 void
118 link_info_dialog(struct session *ses)
120 struct terminal *term = ses->tab->term;
121 struct location *location = cur_loc(ses);
122 struct string msg;
124 if (!location) {
125 nowhere_box(term, NULL);
126 return;
129 if (!init_string(&msg)) return;
131 add_link_info_to_string(&msg, ses);
133 info_box(term, MSGBOX_FREE_TEXT | MSGBOX_SCROLLABLE,
134 N_("Info"), ALIGN_LEFT, msg.source);
138 /* Location info. message box. */
139 void
140 document_info_dialog(struct session *ses)
142 struct terminal *term = ses->tab->term;
143 struct location *location = cur_loc(ses);
144 struct document_view *doc_view;
145 struct string msg;
147 if (!location) {
148 nowhere_box(term, NULL);
149 return;
152 doc_view = current_frame(ses);
154 if (!init_string(&msg)) return;
156 add_to_string(&msg, _("URL", term));
157 add_to_string(&msg, ": ");
159 /* Add the uri with password and post info stripped */
160 add_uri_to_string(&msg, location->vs.uri, URI_PUBLIC);
162 add_char_to_string(&msg, '\n');
164 if (doc_view && doc_view->document->title) {
165 add_format_to_string(&msg, "%s: %s", _("Title", term),
166 doc_view->document->title);
169 add_char_to_string(&msg, '\n');
171 if (doc_view && doc_view->document->cached) {
172 struct cache_entry *cached = doc_view->document->cached;
173 unsigned char *a;
175 add_format_to_string(&msg, "\n%s: %" OFF_PRINT_FORMAT,
176 _("Size", term),
177 (off_print_T) cached->length);
179 if (cached->incomplete) {
180 add_format_to_string(&msg, " (%s)", _("incomplete", term));
183 if (doc_view) {
184 add_format_to_string(&msg, "\n%s: %s", _("Codepage", term),
185 get_cp_name(doc_view->document->cp));
187 if (doc_view->document->cp_status == CP_STATUS_ASSUMED) {
188 add_format_to_string(&msg, " (%s)", _("assumed", term));
189 } else if (doc_view->document->cp_status == CP_STATUS_IGNORED) {
190 add_format_to_string(&msg, " (%s)",
191 _("ignoring server setting", term));
195 a = parse_header(cached->head, "Server", NULL);
196 if (a) {
197 add_format_to_string(&msg, "\n%s: %s",
198 _("Server", term), a);
199 mem_free(a);
202 if (cached->ssl_info) {
203 add_format_to_string(&msg, "\n%s: %s",
204 _("SSL Cipher", term),
205 cached->ssl_info);
207 if (cached->encoding_info) {
208 add_format_to_string(&msg, "\n%s: %s",
209 _("Encoding", term),
210 cached->encoding_info);
213 a = parse_header(cached->head, "Date", NULL);
214 if (a) {
215 add_format_to_string(&msg, "\n%s: %s",
216 _("Date", term), a);
217 mem_free(a);
220 if (cached->last_modified) {
221 add_format_to_string(&msg, "\n%s: %s",
222 _("Last modified", term),
223 cached->last_modified);
226 if (!cached->incomplete) {
227 add_format_to_string(&msg, "\n%s: ",
228 _("Time since loading", term));
229 add_duration_to_string(&msg,
230 time(NULL) - cached->seconds);
235 #ifdef CONFIG_GLOBHIST
237 unsigned char *last_visit = NULL;
238 struct global_history_item *historyitem;
240 add_format_to_string(&msg, "\n%s: ",
241 _("Last visit time", term));
243 historyitem = get_global_history_item(struri(location->vs.uri));
245 if (historyitem) last_visit = ctime(&historyitem->last_visit);
247 /* GNU's documentation says that ctime() can return NULL.
248 * The Open Group Base Specifications Issue 6 implies
249 * otherwise, but is ambiguous. Let's be safe. -- Miciah
251 if (last_visit) {
252 /* The string returned by ctime() includes a newline,
253 * and we don't want that, so we use add_bytes_to_str.
254 * The string always has exactly 25 characters, so add
255 * 24 bytes: The length of the string, minus one for
256 * the newline. -- Miciah
258 add_bytes_to_string(&msg, last_visit, 24);
259 } else {
260 add_to_string(&msg, _("Unknown", term));
263 #endif
265 add_link_info_to_string(&msg, ses);
267 info_box(term, MSGBOX_FREE_TEXT | MSGBOX_SCROLLABLE,
268 N_("Info"), ALIGN_LEFT, msg.source);
271 void
272 cached_header_dialog(struct session *ses, struct cache_entry *cached)
274 int msgbox_flags = 0;
275 unsigned char *title = N_("Header info");
276 unsigned char *headers = NULL;
277 int i = 0, j = 0;
279 if (!cached || !cached->head || !*cached->head)
280 goto display_headers;
282 #ifdef CONFIG_DEBUG
283 /* If |cached->head| starts with a newline, it has been
284 * internally generated, usually to give ELinks-generated
285 * documents (e.g., file:// directory listings) a MIME type
286 * of text/html. */
287 if (*cached->head == '\r')
288 title = N_("Internal header info");
289 #endif
291 headers = mem_alloc(strlen(cached->head) + 1);
292 if (!headers) return;
294 /* Sanitize headers string. */
295 /* XXX: Do we need to check length and limit
296 * it to something reasonable? */
298 while (cached->head[i]) {
299 /* Check for control chars. */
300 if (cached->head[i] < ' '
301 && cached->head[i] != '\n') {
302 /* Ignore '\r' but replace
303 * other control chars with
304 * a visible char. */
305 if (cached->head[i] != '\r') {
306 headers[j] = '*';
307 j++;
309 } else {
310 headers[j] = cached->head[i];
311 j++;
313 i++;
316 /* Ensure null termination. */
317 headers[j] = '\0';
319 /* Remove any trailing newlines. */
320 while (j && headers[--j] == '\n')
321 headers[j] = '\0';
323 if (!*headers)
324 mem_free_set(&headers, NULL);
326 display_headers:
328 if (!headers) {
329 headers = N_("No header info.");
330 } else {
331 msgbox_flags = MSGBOX_FREE_TEXT | MSGBOX_SCROLLABLE;
334 /* Headers info message box. */
335 info_box(ses->tab->term, msgbox_flags,
336 title, ALIGN_LEFT, headers);
339 /* Headers info. message box. */
340 void
341 protocol_header_dialog(struct session *ses)
343 if (!have_location(ses)) {
344 nowhere_box(ses->tab->term, N_("Header info"));
345 return;
348 if (ses->doc_view && ses->doc_view->document)
349 cached_header_dialog(ses, ses->doc_view->document->cached);