1 /* Information about current document and current link */
2
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/types.h>
10 #ifdef HAVE_TIME_H
11 #include <time.h>
12 #endif
13
14 #include "elinks.h"
15
16 #include "bfu/dialog.h"
17 #include "cache/cache.h"
18 #include "dialogs/document.h"
19 #include "document/document.h"
20 #include "document/html/renderer.h"
21 #include "document/view.h"
22 #include "globhist/globhist.h"
23 #include "intl/gettext/libintl.h"
24 #include "protocol/header.h"
25 #include "protocol/uri.h"
26 #include "session/location.h"
27 #include "session/session.h"
28 #include "terminal/terminal.h"
29 #include "terminal/window.h"
30 #include "util/conv.h"
31 #include "util/memory.h"
32 #include "util/string.h"
33 #include "viewer/text/link.h"
34 #include "viewer/text/view.h"
35
36 void
nowhere_box(struct terminal * term,unsigned char * title)37 nowhere_box(struct terminal *term, unsigned char *title)
38 {
39 assert(term);
40 if_assert_failed return;
41
42 if (!title || !*title)
43 title = N_("Info");
44
45 info_box(term, 0, title, ALIGN_CENTER,
46 N_("You are nowhere!"));
47 }
48
49 static void
add_link_info_to_string(struct string * msg,struct session * ses)50 add_link_info_to_string(struct string *msg, struct session *ses)
51 {
52 struct document_view *doc_view = current_frame(ses);
53 struct terminal *term = ses->tab->term;
54 unsigned char *a;
55 struct link *link;
56
57 if (!doc_view) return;
58
59 add_char_to_string(msg, '\n');
60
61 a = get_current_link_info(ses, doc_view);
62 if (a) {
63 add_format_to_string(msg, "\n%s: %s",
64 _("Link", term), a);
65 mem_free(a);
66 }
67
68 a = get_current_link_title(doc_view);
69 if (a) {
70 add_format_to_string(msg, "\n%s: %s",
71 _("Link title", term), a);
72 mem_free(a);
73 }
74
75 link = get_current_link_in_view(doc_view);
76 if (link) {
77 struct string img;
78 #ifdef CONFIG_GLOBHIST
79 struct global_history_item *historyitem;
80 #endif
81
82 if (link->where_img && init_string(&img)) {
83 add_string_uri_to_string(&img, link->where_img,
84 URI_PUBLIC);
85 decode_uri_string_for_display(&img);
86
87 add_format_to_string(msg, "\n%s: %s",
88 _("Link image", term),
89 img.source);
90 done_string(&img);
91 }
92
93 #ifdef CONFIG_GLOBHIST
94 historyitem = get_global_history_item(link->where);
95 if (historyitem) {
96 unsigned char *last_visit;
97
98 last_visit = ctime(&historyitem->last_visit);
99
100 if (last_visit)
101 add_format_to_string(msg,
102 "\n%s: %.24s",
103 _("Link last visit time",
104 term),
105 last_visit);
106
107 if (*historyitem->title)
108 add_format_to_string(msg, "\n%s: %s",
109 _("Link title (from history)",
110 term),
111 historyitem->title);
112 }
113 #endif
114 }
115 }
116
117 /* Location info. message box. */
118 void
document_info_dialog(struct session * ses)119 document_info_dialog(struct session *ses)
120 {
121 struct terminal *term = ses->tab->term;
122 struct location *location = cur_loc(ses);
123 struct document_view *doc_view;
124 struct cache_entry *cached;
125 struct string msg;
126
127 if (!location) {
128 nowhere_box(term, NULL);
129 return;
130 }
131
132 doc_view = current_frame(ses);
133
134 if (!init_string(&msg)) return;
135
136 add_to_string(&msg, _("URL", term));
137 add_to_string(&msg, ": ");
138
139 /* Add the uri with password and post info stripped */
140 add_uri_to_string(&msg, location->vs.uri, URI_PUBLIC);
141
142 add_char_to_string(&msg, '\n');
143
144 if (doc_view && doc_view->document->title) {
145 add_format_to_string(&msg, "%s: %s", _("Title", term),
146 doc_view->document->title);
147 }
148
149 add_char_to_string(&msg, '\n');
150
151 cached = find_in_cache(location->vs.uri);
152 if (cached) {
153 unsigned char *a;
154
155 add_format_to_string(&msg, "\n%s: %" OFF_T_FORMAT,
156 _("Size", term), cached->length);
157
158 if (cached->incomplete) {
159 add_format_to_string(&msg, " (%s)", _("incomplete", term));
160 }
161
162 if (doc_view) {
163 add_format_to_string(&msg, "\n%s: %s", _("Codepage", term),
164 get_cp_name(doc_view->document->cp));
165
166 if (doc_view->document->cp_status == CP_STATUS_ASSUMED) {
167 add_format_to_string(&msg, " (%s)", _("assumed", term));
168 } else if (doc_view->document->cp_status == CP_STATUS_IGNORED) {
169 add_format_to_string(&msg, " (%s)",
170 _("ignoring server setting", term));
171 }
172 }
173
174 a = parse_header(cached->head, "Server", NULL);
175 if (a) {
176 add_format_to_string(&msg, "\n%s: %s",
177 _("Server", term), a);
178 mem_free(a);
179 }
180
181 if (cached->ssl_info) {
182 add_format_to_string(&msg, "\n%s: %s",
183 _("SSL Cipher", term),
184 cached->ssl_info);
185 }
186 if (cached->encoding_info) {
187 add_format_to_string(&msg, "\n%s: %s",
188 _("Encoding", term),
189 cached->encoding_info);
190 }
191
192 a = parse_header(cached->head, "Date", NULL);
193 if (a) {
194 add_format_to_string(&msg, "\n%s: %s",
195 _("Date", term), a);
196 mem_free(a);
197 }
198
199 if (cached->last_modified) {
200 add_format_to_string(&msg, "\n%s: %s",
201 _("Last modified", term),
202 cached->last_modified);
203 }
204
205 }
206
207 #ifdef CONFIG_GLOBHIST
208 {
209 unsigned char *last_visit = NULL;
210 struct global_history_item *historyitem;
211
212 add_format_to_string(&msg, "\n%s: ",
213 _("Last visit time", term));
214
215 historyitem = get_global_history_item(struri(location->vs.uri));
216
217 if (historyitem) last_visit = ctime(&historyitem->last_visit);
218
219 /* GNU's documentation says that ctime() can return NULL.
220 * The Open Group Base Specifications Issue 6 implies
221 * otherwise, but is ambiguous. Let's be safe. -- Miciah
222 */
223 if (last_visit) {
224 /* The string returned by ctime() includes a newline,
225 * and we don't want that, so we use add_bytes_to_str.
226 * The string always has exactly 25 characters, so add
227 * 24 bytes: The length of the string, minus one for
228 * the newline. -- Miciah
229 */
230 add_bytes_to_string(&msg, last_visit, 24);
231 } else {
232 add_to_string(&msg, _("Unknown", term));
233 }
234 }
235 #endif
236
237 add_link_info_to_string(&msg, ses);
238
239 info_box(term, MSGBOX_FREE_TEXT | MSGBOX_SCROLLABLE,
240 N_("Info"), ALIGN_LEFT, msg.source);
241 }
242
243 void
cached_header_dialog(struct session * ses,struct cache_entry * cached)244 cached_header_dialog(struct session *ses, struct cache_entry *cached)
245 {
246 int msgbox_flags = 0;
247 unsigned char *title = N_("Header info");
248 unsigned char *headers = NULL;
249 int i = 0, j = 0;
250
251 if (!cached || !cached->head || !*cached->head)
252 goto display_headers;
253
254 #ifdef CONFIG_DEBUG
255 /* If |cached->head| starts with a newline, it has been
256 * internally generated, usually to give ELinks-generated
257 * documents (e.g., file:// directory listings) a MIME type
258 * of text/html. */
259 if (*cached->head == '\r')
260 title = N_("Internal header info");
261 #endif
262
263 headers = mem_alloc(strlen(cached->head) + 1);
264 if (!headers) return;
265
266 /* Sanitize headers string. */
267 /* XXX: Do we need to check length and limit
268 * it to something reasonable? */
269
270 while (cached->head[i]) {
271 /* Check for control chars. */
272 if (cached->head[i] < ' '
273 && cached->head[i] != '\n') {
274 /* Ignore '\r' but replace
275 * other control chars with
276 * a visible char. */
277 if (cached->head[i] != '\r') {
278 headers[j] = '*';
279 j++;
280 }
281 } else {
282 headers[j] = cached->head[i];
283 j++;
284 }
285 i++;
286 }
287
288 /* Ensure null termination. */
289 headers[j] = '\0';
290
291 /* Remove any trailing newlines. */
292 while (j && headers[--j] == '\n')
293 headers[j] = '\0';
294
295 if (!*headers)
296 mem_free_set(&headers, NULL);
297
298 display_headers:
299
300 if (!headers) {
301 headers = N_("No header info.");
302 } else {
303 msgbox_flags = MSGBOX_FREE_TEXT | MSGBOX_SCROLLABLE;
304 }
305
306 /* Headers info message box. */
307 info_box(ses->tab->term, msgbox_flags,
308 title, ALIGN_LEFT, headers);
309 }
310
311 /* Headers info. message box. */
312 void
protocol_header_dialog(struct session * ses)313 protocol_header_dialog(struct session *ses)
314 {
315 if (!have_location(ses)) {
316 nowhere_box(ses->tab->term, N_("Header info"));
317 return;
318 }
319
320 cached_header_dialog(ses, find_in_cache(cur_loc(ses)->vs.uri));
321 }
322