1 #include "links.h"
2 
3 int retval = RET_OK;
4 
5 void unhandle_basic_signals(struct terminal *);
6 
sig_terminate(struct terminal * t)7 void sig_terminate(struct terminal *t)
8 {
9 	unhandle_basic_signals(t);
10 	terminate_loop = 1;
11 	retval = RET_SIGNAL;
12 }
13 
sig_intr(struct terminal * t)14 void sig_intr(struct terminal *t)
15 {
16 	if (!t) {
17 		unhandle_basic_signals(t);
18 		terminate_loop = 1;
19 	} else {
20 		unhandle_basic_signals(t);
21 		exit_prog(t, NULL, NULL);
22 	}
23 }
24 
sig_ctrl_c(struct terminal * t)25 void sig_ctrl_c(struct terminal *t)
26 {
27 	if (!is_blocked()) kbd_ctrl_c();
28 }
29 
sig_ign(void * x)30 void sig_ign(void *x)
31 {
32 }
33 
34 int fg_poll_timer = -1;
35 void poll_fg(void *t);
36 
sig_tstp(struct terminal * t)37 void sig_tstp(struct terminal *t)
38 {
39 #if defined(SIGSTOP) && !defined(NO_CTRL_Z)
40 #if defined(SIGCONT) && defined(SIGTTOU) && defined(HAVE_GETPID)
41 	pid_t pid, newpid;
42 	EINTRLOOP(pid, getpid());
43 #endif
44 	block_itrm(1);
45 #if defined(SIGCONT) && defined(SIGTTOU) && defined(HAVE_GETPID)
46 	EINTRLOOP(newpid, fork());
47 	if (!newpid) {
48 		while (1) {
49 			int rr;
50 			sleep(1);
51 			EINTRLOOP(rr, kill(pid, SIGCONT));
52 		}
53 	}
54 #endif
55 	{
56 		int rr;
57 		EINTRLOOP(rr, raise(SIGSTOP));
58 	}
59 #if defined(SIGCONT) && defined(SIGTTOU) && defined(HAVE_GETPID)
60 	if (newpid != -1) {
61 		int rr;
62 		EINTRLOOP(rr, kill(newpid, SIGKILL));
63 	}
64 #endif
65 #endif
66 	if (fg_poll_timer != -1) kill_timer(fg_poll_timer);
67 	fg_poll_timer = install_timer(FG_POLL_TIME, poll_fg, t);
68 }
69 
poll_fg(void * t)70 void poll_fg(void *t)
71 {
72 	int r;
73 	fg_poll_timer = -1;
74 	r = unblock_itrm(1);
75 	if (r == -1) {
76 		fg_poll_timer = install_timer(FG_POLL_TIME, poll_fg, t);
77 	}
78 	if (r == -2) {
79 		/* This will unblock externally spawned viewer, if it exists */
80 #ifdef SIGCONT
81 		EINTRLOOP(r, kill(0, SIGCONT));
82 #endif
83 	}
84 }
85 
sig_cont(struct terminal * t)86 void sig_cont(struct terminal *t)
87 {
88 	unblock_itrm(1);
89 }
90 
handle_basic_signals(struct terminal * term)91 void handle_basic_signals(struct terminal *term)
92 {
93 	install_signal_handler(SIGHUP, (void (*)(void *))sig_intr, term, 0);
94 	install_signal_handler(SIGINT, (void (*)(void *))sig_ctrl_c, term, 0);
95 	/*install_signal_handler(SIGTERM, (void (*)(void *))sig_terminate, term, 0);*/
96 #ifdef WIN32
97 	install_signal_handler(SIGQUIT, (void (*)(void *))sig_terminate, term, 0);
98 #endif
99 #ifdef SIGTSTP
100 	install_signal_handler(SIGTSTP, (void (*)(void *))sig_tstp, term, 0);
101 #endif
102 #ifdef SIGTTIN
103 	install_signal_handler(SIGTTIN, (void (*)(void *))sig_tstp, term, 0);
104 #endif
105 #ifdef SIGTTOU
106 	install_signal_handler(SIGTTOU, (void (*)(void *))sig_ign, term, 0);
107 #endif
108 #ifdef SIGCONT
109 	install_signal_handler(SIGCONT, (void (*)(void *))sig_cont, term, 0);
110 #endif
111 }
112 
113 
unhandle_terminal_signals(struct terminal * term)114 void unhandle_terminal_signals(struct terminal *term)
115 {
116 	install_signal_handler(SIGHUP, NULL, NULL, 0);
117 	install_signal_handler(SIGINT, NULL, NULL, 0);
118 #ifdef SIGTSTP
119 	install_signal_handler(SIGTSTP, NULL, NULL, 0);
120 #endif
121 #ifdef SIGTTIN
122 	install_signal_handler(SIGTTIN, NULL, NULL, 0);
123 #endif
124 #ifdef SIGTTOU
125 	install_signal_handler(SIGTTOU, NULL, NULL, 0);
126 #endif
127 #ifdef SIGCONT
128 	install_signal_handler(SIGCONT, NULL, NULL, 0);
129 #endif
130 	if (fg_poll_timer != -1) kill_timer(fg_poll_timer), fg_poll_timer = -1;
131 }
132 
unhandle_basic_signals(struct terminal * term)133 void unhandle_basic_signals(struct terminal *term)
134 {
135 	install_signal_handler(SIGHUP, NULL, NULL, 0);
136 	install_signal_handler(SIGINT, NULL, NULL, 0);
137 	/*install_signal_handler(SIGTERM, NULL, NULL, 0);*/
138 #ifdef SIGTSTP
139 	install_signal_handler(SIGTSTP, NULL, NULL, 0);
140 #endif
141 #ifdef SIGTTIN
142 	install_signal_handler(SIGTTIN, NULL, NULL, 0);
143 #endif
144 #ifdef SIGTTOU
145 	install_signal_handler(SIGTTOU, NULL, NULL, 0);
146 #endif
147 #ifdef SIGCONT
148 	install_signal_handler(SIGCONT, NULL, NULL, 0);
149 #endif
150 	if (fg_poll_timer != -1) kill_timer(fg_poll_timer), fg_poll_timer = -1;
151 }
152 
153 int terminal_pipe[2];
154 
attach_terminal(int in,int out,int ctl,void * info,int len)155 int attach_terminal(int in, int out, int ctl, void *info, int len)
156 {
157 	struct terminal *term;
158 	int rs;
159 	set_nonblock(terminal_pipe[0]);
160 	set_nonblock(terminal_pipe[1]);
161 	handle_trm(in, out, out, terminal_pipe[1], ctl, info, len);
162 	mem_free(info);
163 	if ((term = init_term(terminal_pipe[0], out, win_func))) {
164 		handle_basic_signals(term);	/* OK, this is race condition, but it must be so; GPM installs it's own buggy TSTP handler */
165 		return terminal_pipe[1];
166 	}
167 	EINTRLOOP(rs, close(terminal_pipe[0]));
168 	EINTRLOOP(rs, close(terminal_pipe[1]));
169 	return -1;
170 }
171 
172 struct status dump_stat;
173 off_t dump_pos;
174 
175 int dump_red_count = 0;
176 
end_dump(struct status * stat,void * p)177 void end_dump(struct status *stat, void *p)
178 {
179 	struct cache_entry *ce = stat->ce;
180 	int oh = get_output_handle();
181 	if (oh == -1) return;
182 	if (ce && ce->redirect && dump_red_count++ < MAX_REDIRECTS) {
183 		unsigned char *u, *p;
184 		if (stat->state >= 0) change_connection(stat, NULL, PRI_CANCEL);
185 		u = join_urls(ce->url, ce->redirect);
186 		if (!http_bugs.bug_302_redirect) if (!ce->redirect_get && (p = strchr(ce->url, POST_CHAR))) add_to_strn(&u, p);
187 		load_url(u, stat, PRI_MAIN, 0);
188 		mem_free(u);
189 		return;
190 	}
191 	if (stat->state >= 0 && stat->state < S_TRANS) return;
192 	if (stat->state >= S_TRANS && dmp != D_SOURCE) return;
193 	if (dmp == D_SOURCE) {
194 		if (ce) {
195 			struct fragment *frag;
196 			nextfrag:
197 			foreach(frag, ce->frag) if (frag->offset <= dump_pos && frag->offset + frag->length > dump_pos) {
198 				off_t l;
199 				int w;
200 				l = frag->length - (dump_pos - frag->offset);
201 				if (l > MAXINT) l = MAXINT;
202 				w = hard_write(oh, frag->data + dump_pos - frag->offset, l);
203 				if (w != l) {
204 					detach_connection(stat, dump_pos);
205 					if (w < 0) fprintf(stderr, "Error writing to stdout: %s.\n", strerror(errno));
206 					else fprintf(stderr, "Can't write to stdout.\n");
207 					retval = RET_ERROR;
208 					goto terminate;
209 				}
210 				dump_pos += w;
211 				detach_connection(stat, dump_pos);
212 				goto nextfrag;
213 			}
214 		}
215 		if (stat->state >= 0) return;
216 	} else if (ce) {
217 		struct document_options o;
218 		struct view_state *vs;
219 		struct f_data_c fd;
220 		vs = mem_alloc(sizeof(struct view_state) + strlen(stat->ce->url) + 1);
221 		memset(&o, 0, sizeof(struct document_options));
222 		memset(vs, 0, sizeof(struct view_state));
223 		memset(&fd, 0, sizeof(struct f_data_c));
224 		o.xp = 0;
225 		o.yp = 1;
226 		o.xw = screen_width;
227 		o.yw = 25;
228 		o.col = 0;
229 		o.cp = dump_codepage == -1 ? 0 : dump_codepage;
230 		ds2do(&dds, &o);
231 		o.plain = 0;
232 		o.frames = 0;
233 		memcpy(&o.default_fg, &default_fg, sizeof(struct rgb));
234 		memcpy(&o.default_bg, &default_bg, sizeof(struct rgb));
235 		memcpy(&o.default_link, &default_link, sizeof(struct rgb));
236 		memcpy(&o.default_vlink, &default_vlink, sizeof(struct rgb));
237 		o.framename = "";
238 		init_vs(vs, stat->ce->url);
239 		cached_format_html(vs, &fd, &o);
240 		if (dump_to_file(fd.f_data, oh))
241 			fprintf(stderr, "Error writing to stdout.\n");
242 		detach_formatted(&fd);
243 		destroy_vs(vs);
244 		mem_free(vs);
245 
246 	}
247 	if (stat->state != S__OK) {
248 		unsigned char *m = get_err_msg(stat->state);
249 		fprintf(stderr, "%s\n", get_english_translation(m));
250 		retval = RET_ERROR;
251 		goto terminate;
252 	}
253 	terminate:
254 	terminate_loop = 1;
255 }
256 
257 int g_argc;
258 unsigned char **g_argv;
259 
260 unsigned char *path_to_exe;
261 
262 int init_b = 0;
263 
init()264 void init()
265 {
266 	int uh;
267 	void *info;
268 	int len;
269 	unsigned char *u;
270 	int rs;
271 
272 	init_trans();
273 	set_sigcld();
274 	init_home();
275 	init_cache();
276 	init_keymaps();
277 
278 /* OS/2 has some stupid bug and the pipe must be created before socket :-/ */
279 	if (c_pipe(terminal_pipe)) {
280 		error("ERROR: can't create pipe for internal communication");
281 		retval = RET_FATAL;
282 		goto ttt;
283 	}
284 	if (!(u = parse_options(g_argc - 1, g_argv + 1))) {
285 		retval = RET_SYNTAX;
286 		goto ttt;
287 	}
288 	if (!dmp) {
289 		init_os_terminal();
290 	}
291 	if (!no_connect && (uh = bind_to_af_unix()) != -1) {
292 		EINTRLOOP(rs, close(terminal_pipe[0]));
293 		EINTRLOOP(rs, close(terminal_pipe[1]));
294 		if (!(info = create_session_info(base_session, u, &len))) {
295 			retval = RET_FATAL;
296 			goto ttt;
297 		}
298 		handle_trm(get_input_handle(), get_output_handle(), uh, uh, get_ctl_handle(), info, len);
299 		handle_basic_signals(NULL);	/* OK, this is race condition, but it must be so; GPM installs it's own buggy TSTP handler */
300 		mem_free(info);
301 		return;
302 	}
303 	if ((dds.assume_cp = get_cp_index("ISO-8859-1")) == -1) dds.assume_cp = 0;
304 	load_config();
305 	init_b = 1;
306 	read_bookmarks();
307 	load_url_history();
308 	init_cookies();
309 	u = parse_options(g_argc - 1, g_argv + 1);
310 	if (!u) {
311 		ttt:
312 		terminate_loop = 1;
313 		return;
314 	}
315 	if (!dmp) {
316 		if (!((info = create_session_info(base_session, u, &len)) && attach_terminal(get_input_handle(), get_output_handle(), get_ctl_handle(), info, len) != -1)) {
317 			retval = RET_FATAL;
318 			terminate_loop = 1;
319 		}
320 	} else {
321 		unsigned char *uu, *wd;
322 		EINTRLOOP(rs, close(terminal_pipe[0]));
323 		EINTRLOOP(rs, close(terminal_pipe[1]));
324 		if (!*u) {
325 			fprintf(stderr, "URL expected after %s\n.", dmp == D_DUMP ? "-dump" : "-source");
326 			retval = RET_SYNTAX;
327 			goto ttt;
328 		}
329 		dump_stat.end = end_dump;
330 		dump_pos = 0;
331 		if (!(uu = translate_url(u, wd = get_cwd()))) uu = stracpy(u);
332 		if (load_url(uu, &dump_stat, PRI_MAIN, 0)) {
333 			retval = RET_FATAL;
334 			goto ttt;
335 		}
336 		mem_free(uu);
337 		if (wd) mem_free(wd);
338 	}
339 }
340 
terminate_all_subsystems()341 void terminate_all_subsystems()
342 {
343 	af_unix_close();
344 	destroy_all_sessions();
345 	check_bottom_halves();
346 	abort_all_downloads();
347 	check_bottom_halves();
348 	destroy_all_terminals();
349 	check_bottom_halves();
350 	free_all_itrms();
351 	abort_all_connections();
352 #ifdef HAVE_SSL
353 	ssl_finish();
354 #endif
355 	shrink_memory(1);
356 	if (init_b) save_url_history();
357 	free_history_lists();
358 	free_term_specs();
359 	free_types();
360 	if (init_b) finalize_bookmarks();
361 	free_keymaps();
362 	free_conv_table();
363 	free_blacklist();
364 	if (init_b) cleanup_cookies();
365 	check_bottom_halves();
366 	end_config();
367 	free_strerror_buf();
368 	shutdown_trans();
369 	terminate_osdep();
370 	if (fg_poll_timer != -1) kill_timer(fg_poll_timer), fg_poll_timer = -1;
371 }
372 
main(int argc,char * argv[])373 int main(int argc, char *argv[])
374 {
375 	g_argc = argc;
376 	g_argv = (unsigned char **)argv;
377 
378 	init_os();
379 
380 	get_path_to_exe();
381 
382 	select_loop(init);
383 	terminate_all_subsystems();
384 
385 	check_memory_leaks();
386 	return retval;
387 }
388 
shrink_memory(int u)389 void shrink_memory(int u)
390 {
391 	shrink_dns_cache(u);
392 	shrink_format_cache(u);
393 	garbage_collection(u);
394 	delete_unused_format_cache_entries();
395 }
396