1 | /********************************************************************** <BR>
|
---|
2 | This file is part of Crack dot Com's free source code release of
|
---|
3 | Golgotha. <a href="http://www.crack.com/golgotha_release"> <BR> for
|
---|
4 | information about compiling & licensing issues visit this URL</a>
|
---|
5 | <PRE> If that doesn't help, contact Jonathan Clark at
|
---|
6 | golgotha_source@usa.net (Subject should have "GOLG" in it)
|
---|
7 | ***********************************************************************/
|
---|
8 |
|
---|
9 | #include "network/net_prot.hh"
|
---|
10 |
|
---|
11 | #include "win.hh"
|
---|
12 | #include "threads/threads.hh"
|
---|
13 | #include "fb_thread.hh"
|
---|
14 | #include "font/font.hh"
|
---|
15 | #include "gui/button.hh"
|
---|
16 | #include "gui/text.hh"
|
---|
17 | #include "url.hh"
|
---|
18 | #include "network/net_sock.hh"
|
---|
19 | #include "lisp/lisp.hh"
|
---|
20 | #include <ctype.h>
|
---|
21 |
|
---|
22 |
|
---|
23 | char *fb_thread_window::get_error_string()
|
---|
24 | {
|
---|
25 | switch (last_error)
|
---|
26 | {
|
---|
27 | case FB_NO_ERROR : return "ok"; break;
|
---|
28 | case FB_TIMED_OUT : return "timeout"; break;
|
---|
29 | case FB_URL_TOO_BIG : return "url too big"; break;
|
---|
30 | case FB_END_OF_STREAM : return "end of stream"; break;
|
---|
31 | case FB_NOT_IN_INCLUDE_LIST : return "not in include list"; break;
|
---|
32 | case FB_NO_EXTENSION : return "no file extension"; break;
|
---|
33 | case FB_NO_FILENAME : return "no filename"; break;
|
---|
34 | case FB_FILE_EXSIST : return "file exsist"; break;
|
---|
35 | case FB_NO_WRITE_OPEN : return "couldn't open write file"; break;
|
---|
36 | case FB_IN_EXCLUDE_LIST : return "in exclusion list"; break;
|
---|
37 | case FB_NO_CONNECT : return "connect failed"; break;
|
---|
38 | case FB_USER_ABORTED : return "user aborted"; break;
|
---|
39 | default : return "unknown error"; break;
|
---|
40 | }
|
---|
41 | last_error=FB_NO_ERROR;
|
---|
42 | }
|
---|
43 |
|
---|
44 |
|
---|
45 |
|
---|
46 | void fb_thread_window::stop_thread()
|
---|
47 | {
|
---|
48 | if (state!=FB_WAITING && state!=FB_DONE_READING)
|
---|
49 | stopping=1;
|
---|
50 |
|
---|
51 | while (state!=FB_WAITING && state!=FB_DONE_READING)
|
---|
52 | i4_thread_yield();
|
---|
53 | }
|
---|
54 |
|
---|
55 | void fb_thread_window::add_button(char *name, cmd_type cmd)
|
---|
56 | {
|
---|
57 | i4_text_window_class *tw=new i4_text_window_class(name, style,
|
---|
58 | style->font_hint->small_font);
|
---|
59 |
|
---|
60 | i4_button_class *b;
|
---|
61 | b=new i4_button_class(0, tw, style, new i4_event_reaction_class(this, cmd));
|
---|
62 | b->set_popup(i4_T);
|
---|
63 | button_x-=(int)b->width();
|
---|
64 | add_child(button_x, 0, b);
|
---|
65 | }
|
---|
66 |
|
---|
67 |
|
---|
68 |
|
---|
69 |
|
---|
70 | void fb_thread_window::read_data()
|
---|
71 | {
|
---|
72 | w8 packet[1024];
|
---|
73 | int s=sock->read(packet,1024);
|
---|
74 | last_read.get();
|
---|
75 |
|
---|
76 | if (s>0) // read 0 or less, assume end of stream
|
---|
77 | {
|
---|
78 | if (save_file)
|
---|
79 | {
|
---|
80 | save_file->write(packet, s);
|
---|
81 | save_buffer_size+=s;
|
---|
82 | }
|
---|
83 | else
|
---|
84 | {
|
---|
85 | // we are going to overflow our buffer
|
---|
86 | if (save_buffer_size+s > FB_MAX_SAVE_BUFFER_SIZE)
|
---|
87 | {
|
---|
88 | last_error=FB_URL_TOO_BIG;
|
---|
89 | state=FB_DONE_READING; // tell main program to process what we read of url
|
---|
90 | }
|
---|
91 | else
|
---|
92 | {
|
---|
93 | memcpy(save_buffer + save_buffer_size, packet, s);
|
---|
94 | save_buffer_size+=s;
|
---|
95 | }
|
---|
96 | }
|
---|
97 | }
|
---|
98 | else
|
---|
99 | {
|
---|
100 | last_error=FB_END_OF_STREAM;
|
---|
101 |
|
---|
102 | if (save_file)
|
---|
103 | {
|
---|
104 | close_save_file(i4_F);
|
---|
105 | state=FB_WAITING; // ready for another request
|
---|
106 | save_buffer_size=0;
|
---|
107 | }
|
---|
108 | else
|
---|
109 | {
|
---|
110 | state=FB_DONE_READING; // tell main program to process this url
|
---|
111 |
|
---|
112 | }
|
---|
113 |
|
---|
114 | if (sock)
|
---|
115 | {
|
---|
116 | delete sock;
|
---|
117 | sock=0;
|
---|
118 | }
|
---|
119 | }
|
---|
120 | }
|
---|
121 |
|
---|
122 | char *nocase_strstr(char *hay, char *needle)
|
---|
123 | {
|
---|
124 | while (*hay)
|
---|
125 | {
|
---|
126 | char *a1, *a2;
|
---|
127 | int not_equal=0;
|
---|
128 |
|
---|
129 | for (a1=hay, a2=needle; *a1 && *a2; )
|
---|
130 | {
|
---|
131 | if (toupper(*a1)!=toupper(*a2))
|
---|
132 | not_equal=1;
|
---|
133 | a1++;
|
---|
134 | a2++;
|
---|
135 | }
|
---|
136 |
|
---|
137 | if (*a2) not_equal=1;
|
---|
138 |
|
---|
139 | if (!not_equal)
|
---|
140 | return hay;
|
---|
141 |
|
---|
142 | hay++;
|
---|
143 | }
|
---|
144 | return 0;
|
---|
145 | }
|
---|
146 |
|
---|
147 | void fb_thread_window::set_url(fb_url *new_url)
|
---|
148 | {
|
---|
149 | stop_thread();
|
---|
150 | save_buffer_size=0;
|
---|
151 |
|
---|
152 |
|
---|
153 | close_save_file();
|
---|
154 |
|
---|
155 | if (sock)
|
---|
156 | {
|
---|
157 | delete sock;
|
---|
158 | sock=0;
|
---|
159 | }
|
---|
160 |
|
---|
161 | if (url)
|
---|
162 | delete url;
|
---|
163 |
|
---|
164 | url=new_url;
|
---|
165 |
|
---|
166 | li_object *o;
|
---|
167 |
|
---|
168 | for (o=li_get_value("exclude_sub_strings",0); o; o=li_cdr(o,0))
|
---|
169 | if (nocase_strstr(url->full_name, li_string::get(li_car(o,0),0)->value()))
|
---|
170 | {
|
---|
171 | last_error=FB_IN_EXCLUDE_LIST;
|
---|
172 | state=FB_DONE_READING;
|
---|
173 | return ;
|
---|
174 | }
|
---|
175 |
|
---|
176 | int save=0;
|
---|
177 | char *ext=url->get_extension();
|
---|
178 | if (ext)
|
---|
179 | {
|
---|
180 |
|
---|
181 | o=li_get_value("include_sub_strings");
|
---|
182 | if (o)
|
---|
183 | {
|
---|
184 | int ok=0;
|
---|
185 |
|
---|
186 | while (o && !ok)
|
---|
187 | {
|
---|
188 | li_object *i=li_car(o,0);
|
---|
189 | if (fb_strneq( li_get_string(li_car(i,0),0), ext, strlen(ext)))
|
---|
190 | {
|
---|
191 | i=li_cdr(i,0);
|
---|
192 | if (!i)
|
---|
193 | ok=1;
|
---|
194 | else
|
---|
195 | {
|
---|
196 | for (i=li_cdr(i,0); i; i=li_cdr(i,0))
|
---|
197 | if (nocase_strstr(url->full_name, li_string::get(li_car(i,0),0)->value()))
|
---|
198 | ok=1;
|
---|
199 |
|
---|
200 | if (!ok)
|
---|
201 | i4_debug->printf("not listed '%s'\n", url->full_name);
|
---|
202 |
|
---|
203 | }
|
---|
204 | }
|
---|
205 | o=li_cdr(o,0);
|
---|
206 | }
|
---|
207 |
|
---|
208 | int l=strlen(url->full_name)-1;
|
---|
209 | if (!ok && url->full_name[l]!='/' && url->full_name[l]!='\\')
|
---|
210 | {
|
---|
211 | last_error=FB_NOT_IN_INCLUDE_LIST;
|
---|
212 | state=FB_DONE_READING;
|
---|
213 | return ;
|
---|
214 | }
|
---|
215 | }
|
---|
216 |
|
---|
217 | for (o=li_get_value("save_extensions",0); o; o=li_cdr(o,0))
|
---|
218 | if (strcmp(li_string::get(li_car(o,0),0)->value(), ext)==0)
|
---|
219 | save=1;
|
---|
220 |
|
---|
221 | }
|
---|
222 |
|
---|
223 |
|
---|
224 |
|
---|
225 | if (save)
|
---|
226 | {
|
---|
227 | char *fn=url->get_filename();
|
---|
228 | if (!fn)
|
---|
229 | {
|
---|
230 | last_error=FB_NO_FILENAME;
|
---|
231 | state=FB_DONE_READING;
|
---|
232 | return ;
|
---|
233 | }
|
---|
234 |
|
---|
235 | char filename[200];
|
---|
236 | sprintf(filename, "%s%s", li_string::get(li_get_value("save_path",0),0)->value(), fn);
|
---|
237 |
|
---|
238 | i4_file_status_struct stat;
|
---|
239 |
|
---|
240 | if (i4_get_status(filename, stat))
|
---|
241 | {
|
---|
242 | last_error=FB_FILE_EXSIST;
|
---|
243 | state=FB_DONE_READING;
|
---|
244 | return ;
|
---|
245 | }
|
---|
246 |
|
---|
247 | save_file=i4_open(filename, I4_WRITE);
|
---|
248 | if (!save_file)
|
---|
249 | {
|
---|
250 | last_error=FB_NO_WRITE_OPEN;
|
---|
251 | state=FB_DONE_READING;
|
---|
252 | return ;
|
---|
253 | }
|
---|
254 | }
|
---|
255 |
|
---|
256 | state=FB_CONNECTING; // let the thread do the nameserver lookup
|
---|
257 | }
|
---|
258 |
|
---|
259 |
|
---|
260 | void fb_thread_window::receive_event(i4_event *ev)
|
---|
261 | {
|
---|
262 | if (ev->type()==i4_event::USER_MESSAGE)
|
---|
263 | {
|
---|
264 | switch (((i4_user_message_event_class *)ev)->sub_type)
|
---|
265 | {
|
---|
266 | case PAUSE :
|
---|
267 | if (state==FB_READING)
|
---|
268 | state=FB_SUSPENDED_READ;
|
---|
269 | else if (state==FB_SUSPENDED_READ)
|
---|
270 | state=FB_READING;
|
---|
271 | break;
|
---|
272 |
|
---|
273 | case ABORT :
|
---|
274 | stopping=1;
|
---|
275 | break;
|
---|
276 |
|
---|
277 | case BAN_DIR :
|
---|
278 | case BAN_SITE :
|
---|
279 | break;
|
---|
280 | }
|
---|
281 | }
|
---|
282 |
|
---|
283 | i4_parent_window_class::receive_event(ev);
|
---|
284 | }
|
---|
285 |
|
---|
286 | fb_thread_window::fb_thread_window(w16 w, w16 h, i4_graphical_style_class *style)
|
---|
287 | : i4_parent_window_class(w,h), style(style)
|
---|
288 | {
|
---|
289 | stopping=0;
|
---|
290 | prot=i4_get_typed_protocol(I4_TCPIP);
|
---|
291 | if (!prot) i4_error("no TCPIP in program");
|
---|
292 |
|
---|
293 | save_buffer_size=0;
|
---|
294 | sock=0;
|
---|
295 | save_file=0;
|
---|
296 | url=0;
|
---|
297 |
|
---|
298 | last_error=FB_NO_ERROR;
|
---|
299 | state=FB_THREAD_INIT;
|
---|
300 | i4_add_thread(fb_thread, 100*1024, this);
|
---|
301 |
|
---|
302 | button_x=width();
|
---|
303 |
|
---|
304 | add_button("Pause", PAUSE);
|
---|
305 | add_button("Abort", ABORT);
|
---|
306 | add_button("Ban Dir", BAN_DIR);
|
---|
307 | add_button("Ban Site", BAN_SITE);
|
---|
308 | }
|
---|
309 |
|
---|
310 | // called from main program to see if window needs to be redrawn
|
---|
311 | void fb_thread_window::update() // check to see if we need to update the window
|
---|
312 | {
|
---|
313 | i4_time_class now;
|
---|
314 |
|
---|
315 | if (now.milli_diff(last_refresh)>200) // refresh every .2 secs
|
---|
316 | {
|
---|
317 | if (last_state!=state ||
|
---|
318 | last_save_buffer_size!=save_buffer_size)
|
---|
319 | request_redraw(i4_F);
|
---|
320 | }
|
---|
321 | }
|
---|
322 |
|
---|
323 |
|
---|
324 | // called by main program when window some time after window calls request_redraw
|
---|
325 | void fb_thread_window::parent_draw(i4_draw_context_class &context)
|
---|
326 | {
|
---|
327 | style->deco_neutral_fill(local_image, 0,0, width()-1, height()-1, context);
|
---|
328 |
|
---|
329 | i4_font_class *font=style->font_hint->small_font;
|
---|
330 | i4_font_class *bfont=style->font_hint->normal_font;
|
---|
331 |
|
---|
332 | char *state_names[]={"Thread Init",
|
---|
333 | "Idle",
|
---|
334 | "Connecting",
|
---|
335 | "Reading",
|
---|
336 | "Paused",
|
---|
337 | "Done Reading",
|
---|
338 | "Stopping",
|
---|
339 | "Quiting",
|
---|
340 | "Done"};
|
---|
341 |
|
---|
342 | bfont->set_color(0xffff00);
|
---|
343 |
|
---|
344 | int x=0, y=0;
|
---|
345 | bfont->put_string(local_image, x,y, state_names[state], context);
|
---|
346 | y+=bfont->height(state_names[state])+4;
|
---|
347 |
|
---|
348 | if (url && state==FB_CONNECTING || state==FB_READING ||
|
---|
349 | state==FB_DONE_READING || state==FB_SUSPENDED_READ)
|
---|
350 | {
|
---|
351 | font->set_color(0x7f);
|
---|
352 | font->put_string(local_image, x,y, url->full_name, context);
|
---|
353 | }
|
---|
354 | y+=font->largest_height();
|
---|
355 |
|
---|
356 |
|
---|
357 | if (state==FB_READING || state==FB_DONE_READING || state==FB_SUSPENDED_READ)
|
---|
358 | {
|
---|
359 | char buf[100];
|
---|
360 | font->set_color(0x7f0000);
|
---|
361 | sprintf(buf, "%d bytes read", save_buffer_size);
|
---|
362 | font->put_string(local_image, x,y, buf, context);
|
---|
363 | }
|
---|
364 |
|
---|
365 | last_state=state;
|
---|
366 | last_save_buffer_size=save_buffer_size;
|
---|
367 |
|
---|
368 | last_refresh.get();
|
---|
369 |
|
---|
370 | }
|
---|
371 |
|
---|
372 | // waits for thread to stop before closing the window
|
---|
373 | fb_thread_window::~fb_thread_window()
|
---|
374 | {
|
---|
375 | state=FB_THREAD_QUITING;
|
---|
376 | while (state!=FB_THREAD_DONE)
|
---|
377 | i4_thread_yield();
|
---|
378 | }
|
---|
379 |
|
---|
380 |
|
---|
381 | void fb_thread_window::check_for_timeout()
|
---|
382 | {
|
---|
383 | i4_time_class now;
|
---|
384 | int secs=now.milli_diff(last_read)/1000; // time in secs
|
---|
385 |
|
---|
386 | if (secs!=last_sec)
|
---|
387 | {
|
---|
388 | last_sec=secs;
|
---|
389 |
|
---|
390 | for (li_object *o=li_get_value("timeouts",0); o; o=li_cdr(o,0))
|
---|
391 | {
|
---|
392 | int size=li_int::get(li_first(li_car(o,0),0),0)->value();
|
---|
393 | int tout=li_int::get(li_second(li_car(o,0),0),0)->value();
|
---|
394 |
|
---|
395 |
|
---|
396 | if (save_buffer_size<size && secs>tout)
|
---|
397 | {
|
---|
398 | last_error=FB_TIMED_OUT;
|
---|
399 | state=FB_DONE_READING;
|
---|
400 | return ;
|
---|
401 | }
|
---|
402 | }
|
---|
403 | }
|
---|
404 | }
|
---|
405 |
|
---|
406 | // closes save file if need, and deletes it if it's too small
|
---|
407 | void fb_thread_window::close_save_file(int wait_on_thread)
|
---|
408 | {
|
---|
409 | if (save_file)
|
---|
410 | {
|
---|
411 | if (wait_on_thread)
|
---|
412 | stop_thread();
|
---|
413 |
|
---|
414 | int need_del = save_file->tell() < li_int::get(li_get_value("save_min_size",0),0)->value() ? 1 : 0;
|
---|
415 |
|
---|
416 | delete save_file;
|
---|
417 | save_file=0;
|
---|
418 |
|
---|
419 | if (url && need_del)
|
---|
420 | {
|
---|
421 | char filename[200];
|
---|
422 | sprintf(filename, "%s%s", li_string::get(li_get_value("save_path",0),0)->value(),
|
---|
423 | url->get_filename());
|
---|
424 | i4_unlink(filename);
|
---|
425 | }
|
---|
426 | }
|
---|
427 | }
|
---|