/**********************************************************************
This file is part of Crack dot Com's free source code release of
Golgotha.
for
information about compiling & licensing issues visit this URL
If that doesn't help, contact Jonathan Clark at golgotha_source@usa.net (Subject should have "GOLG" in it) ***********************************************************************/ #include "network/net_prot.hh" #include "win.hh" #include "threads/threads.hh" #include "fb_thread.hh" #include "font/font.hh" #include "gui/button.hh" #include "gui/text.hh" #include "url.hh" #include "network/net_sock.hh" #include "lisp/lisp.hh" #includechar *fb_thread_window::get_error_string() { switch (last_error) { case FB_NO_ERROR : return "ok"; break; case FB_TIMED_OUT : return "timeout"; break; case FB_URL_TOO_BIG : return "url too big"; break; case FB_END_OF_STREAM : return "end of stream"; break; case FB_NOT_IN_INCLUDE_LIST : return "not in include list"; break; case FB_NO_EXTENSION : return "no file extension"; break; case FB_NO_FILENAME : return "no filename"; break; case FB_FILE_EXSIST : return "file exsist"; break; case FB_NO_WRITE_OPEN : return "couldn't open write file"; break; case FB_IN_EXCLUDE_LIST : return "in exclusion list"; break; case FB_NO_CONNECT : return "connect failed"; break; case FB_USER_ABORTED : return "user aborted"; break; default : return "unknown error"; break; } last_error=FB_NO_ERROR; } void fb_thread_window::stop_thread() { if (state!=FB_WAITING && state!=FB_DONE_READING) stopping=1; while (state!=FB_WAITING && state!=FB_DONE_READING) i4_thread_yield(); } void fb_thread_window::add_button(char *name, cmd_type cmd) { i4_text_window_class *tw=new i4_text_window_class(name, style, style->font_hint->small_font); i4_button_class *b; b=new i4_button_class(0, tw, style, new i4_event_reaction_class(this, cmd)); b->set_popup(i4_T); button_x-=(int)b->width(); add_child(button_x, 0, b); } void fb_thread_window::read_data() { w8 packet[1024]; int s=sock->read(packet,1024); last_read.get(); if (s>0) // read 0 or less, assume end of stream { if (save_file) { save_file->write(packet, s); save_buffer_size+=s; } else { // we are going to overflow our buffer if (save_buffer_size+s > FB_MAX_SAVE_BUFFER_SIZE) { last_error=FB_URL_TOO_BIG; state=FB_DONE_READING; // tell main program to process what we read of url } else { memcpy(save_buffer + save_buffer_size, packet, s); save_buffer_size+=s; } } } else { last_error=FB_END_OF_STREAM; if (save_file) { close_save_file(i4_F); state=FB_WAITING; // ready for another request save_buffer_size=0; } else { state=FB_DONE_READING; // tell main program to process this url } if (sock) { delete sock; sock=0; } } } char *nocase_strstr(char *hay, char *needle) { while (*hay) { char *a1, *a2; int not_equal=0; for (a1=hay, a2=needle; *a1 && *a2; ) { if (toupper(*a1)!=toupper(*a2)) not_equal=1; a1++; a2++; } if (*a2) not_equal=1; if (!not_equal) return hay; hay++; } return 0; } void fb_thread_window::set_url(fb_url *new_url) { stop_thread(); save_buffer_size=0; close_save_file(); if (sock) { delete sock; sock=0; } if (url) delete url; url=new_url; li_object *o; for (o=li_get_value("exclude_sub_strings",0); o; o=li_cdr(o,0)) if (nocase_strstr(url->full_name, li_string::get(li_car(o,0),0)->value())) { last_error=FB_IN_EXCLUDE_LIST; state=FB_DONE_READING; return ; } int save=0; char *ext=url->get_extension(); if (ext) { o=li_get_value("include_sub_strings"); if (o) { int ok=0; while (o && !ok) { li_object *i=li_car(o,0); if (fb_strneq( li_get_string(li_car(i,0),0), ext, strlen(ext))) { i=li_cdr(i,0); if (!i) ok=1; else { for (i=li_cdr(i,0); i; i=li_cdr(i,0)) if (nocase_strstr(url->full_name, li_string::get(li_car(i,0),0)->value())) ok=1; if (!ok) i4_debug->printf("not listed '%s'\n", url->full_name); } } o=li_cdr(o,0); } int l=strlen(url->full_name)-1; if (!ok && url->full_name[l]!='/' && url->full_name[l]!='\\') { last_error=FB_NOT_IN_INCLUDE_LIST; state=FB_DONE_READING; return ; } } for (o=li_get_value("save_extensions",0); o; o=li_cdr(o,0)) if (strcmp(li_string::get(li_car(o,0),0)->value(), ext)==0) save=1; } if (save) { char *fn=url->get_filename(); if (!fn) { last_error=FB_NO_FILENAME; state=FB_DONE_READING; return ; } char filename[200]; sprintf(filename, "%s%s", li_string::get(li_get_value("save_path",0),0)->value(), fn); i4_file_status_struct stat; if (i4_get_status(filename, stat)) { last_error=FB_FILE_EXSIST; state=FB_DONE_READING; return ; } save_file=i4_open(filename, I4_WRITE); if (!save_file) { last_error=FB_NO_WRITE_OPEN; state=FB_DONE_READING; return ; } } state=FB_CONNECTING; // let the thread do the nameserver lookup } void fb_thread_window::receive_event(i4_event *ev) { if (ev->type()==i4_event::USER_MESSAGE) { switch (((i4_user_message_event_class *)ev)->sub_type) { case PAUSE : if (state==FB_READING) state=FB_SUSPENDED_READ; else if (state==FB_SUSPENDED_READ) state=FB_READING; break; case ABORT : stopping=1; break; case BAN_DIR : case BAN_SITE : break; } } i4_parent_window_class::receive_event(ev); } fb_thread_window::fb_thread_window(w16 w, w16 h, i4_graphical_style_class *style) : i4_parent_window_class(w,h), style(style) { stopping=0; prot=i4_get_typed_protocol(I4_TCPIP); if (!prot) i4_error("no TCPIP in program"); save_buffer_size=0; sock=0; save_file=0; url=0; last_error=FB_NO_ERROR; state=FB_THREAD_INIT; i4_add_thread(fb_thread, 100*1024, this); button_x=width(); add_button("Pause", PAUSE); add_button("Abort", ABORT); add_button("Ban Dir", BAN_DIR); add_button("Ban Site", BAN_SITE); } // called from main program to see if window needs to be redrawn void fb_thread_window::update() // check to see if we need to update the window { i4_time_class now; if (now.milli_diff(last_refresh)>200) // refresh every .2 secs { if (last_state!=state || last_save_buffer_size!=save_buffer_size) request_redraw(i4_F); } } // called by main program when window some time after window calls request_redraw void fb_thread_window::parent_draw(i4_draw_context_class &context) { style->deco_neutral_fill(local_image, 0,0, width()-1, height()-1, context); i4_font_class *font=style->font_hint->small_font; i4_font_class *bfont=style->font_hint->normal_font; char *state_names[]={"Thread Init", "Idle", "Connecting", "Reading", "Paused", "Done Reading", "Stopping", "Quiting", "Done"}; bfont->set_color(0xffff00); int x=0, y=0; bfont->put_string(local_image, x,y, state_names[state], context); y+=bfont->height(state_names[state])+4; if (url && state==FB_CONNECTING || state==FB_READING || state==FB_DONE_READING || state==FB_SUSPENDED_READ) { font->set_color(0x7f); font->put_string(local_image, x,y, url->full_name, context); } y+=font->largest_height(); if (state==FB_READING || state==FB_DONE_READING || state==FB_SUSPENDED_READ) { char buf[100]; font->set_color(0x7f0000); sprintf(buf, "%d bytes read", save_buffer_size); font->put_string(local_image, x,y, buf, context); } last_state=state; last_save_buffer_size=save_buffer_size; last_refresh.get(); } // waits for thread to stop before closing the window fb_thread_window::~fb_thread_window() { state=FB_THREAD_QUITING; while (state!=FB_THREAD_DONE) i4_thread_yield(); } void fb_thread_window::check_for_timeout() { i4_time_class now; int secs=now.milli_diff(last_read)/1000; // time in secs if (secs!=last_sec) { last_sec=secs; for (li_object *o=li_get_value("timeouts",0); o; o=li_cdr(o,0)) { int size=li_int::get(li_first(li_car(o,0),0),0)->value(); int tout=li_int::get(li_second(li_car(o,0),0),0)->value(); if (save_buffer_size tout) { last_error=FB_TIMED_OUT; state=FB_DONE_READING; return ; } } } } // closes save file if need, and deletes it if it's too small void fb_thread_window::close_save_file(int wait_on_thread) { if (save_file) { if (wait_on_thread) stop_thread(); int need_del = save_file->tell() < li_int::get(li_get_value("save_min_size",0),0)->value() ? 1 : 0; delete save_file; save_file=0; if (url && need_del) { char filename[200]; sprintf(filename, "%s%s", li_string::get(li_get_value("save_path",0),0)->value(), url->get_filename()); i4_unlink(filename); } } }