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