PUBLIC int NET_GetURL ( URL_Struct *URL_s, FO_Present_Types output_types, MWContext *window_id, Net_GetUrlExitFunc *exit_routine ) { ActiveEntry_t ae = new ActiveEntry_t; ae->down_queue = new EventQueue_t; ae->up_queue = new EventQueue_t; ae->url = URL_s; ae->out = output_types; ae->handle = BuildContextAndData(window_id); ae->end = exit_routine; AddEntry(active_list, ae); FE_RegisterMonitorCallback(ae->up_queue->monitor, NET_ProcessNet); StartThread(ae->thread, do_URL, ae); Event_t e = new Event_t(handle_URL, cleanup_event); e->data = ae; EnqueueEvent(ae->down_queue, e); return; } PRIVATE void do_URL ( ActiveEntry_t ae ) { while( 1 ) { Event_t e = GetEvent(ae->down_queue); HandleEvent(e); } } PRIVATE void handle_URL ( Event_t self ) { URL_type_t type = NET_URL_Type(self->data->url); Protocol_Module_t module = LoadProtocolModule(type); (*module->handle_URL)(self); } DYNAMIC void HTTP_handle_URL ( Event_t self ) { ActiveEntry_t ae = self->data; URL_Struct *url = ae->url; AsynchProgress(self, "Connecting to %s.", url->host); Socket_t s = NET_Connect(url->address, url->host, url->port); if( s == -1 ) { Event_t oops = new Event_t(display_error, cleanup_event); oops->data = CANT_CONNECT_ERROR; EnqueueEvent(ae->up_queue, oops); return; } AsynchProgress(ae, "Connected."); char *command = NET_BuildCommand(...); if( command == NULL ) { // handle the error.. } NET_BlockingWrite(s, command, strlen(command)); ParseHTTPMimeHeaders(s, url); if( url->authorisation_required ) { url->authinfo = AsynchAskForAuthString(ae, url); // reconnect, etc.. } Stream_t stream = AsynchBuildStream(ae, url, ae->out); char buffer[ SIZE ]; int amount; Event_t push = new Event_t(push_data, cleanup_event); while( (amount = NET_BlockingRead(s, buffer)) > 0 ) { push->data = buffer; push->amount = amount; push->stream = stream; EnqueueSynchronousEvent(ae->up_queue, push); } if( amount == -1 ) { // handle error as above } Event_t done = new Event_t(final_event, cleanup_event); EnqueueEvent(ae->up_queue, done); return; } PUBLIC void AsynchProgress ( ActiveEntry_t ae, char *directive, args.. ) { Event_t e = new Event_t(Progress, cleanup_event); e->data = sprint(directive, args); EnqueueEvent(ae->up_queue, e); } PUBLIC AuthInfo_t AsynchAskForAuthString ( ActiveEntry_t ae, URL_Struct *url ) { Event_t e = new Event_t(AskForAuthString, cleanup_event); e->data = url; return EnqueueSynchronousEvent(ae->up_queue, e); } PUBLIC Stream_t AsynchBuildStream ( ActiveEntry_t ae, URL_Struct *url, FO_Present_Types out ) { Event_t e = new Event_t(BuildStream, cleanup_event); e->data = url; e->moredata = out return EnqueueSynchronousEvent(ae->up_queue, e); } PUBLIC void NET_ProcessNet ( Monitor_t which ) { ActiveEntry_t ae = FindEntry(active_list, which); Event_t e = GetEvent(ae->up_queue); HandleEvent(e); } PRIVATE void Progress ( Event_t self ) { FE_Progress(self->data); } PRIVATE AuthInfo_t AskForAuthString ( Event_t self ) { FE_whatever(...) return result; } PRIVATE Stream_t BuildStream ( Event_t self ) { return NET_StreamBuilder(self->etc...); } PRIVATE void push_data ( Event_t self ) { int amount = (*self->stream->write_ready)(self->handle); (*self->stream->write)(self->handle, self->data, amount); if( amount < self->amount ) { // requeue remaining data at head of queue } return; } PUBLIC void NET_Interrupt ( criteria ) { ActiveEntry_t ae; foreach( ae in active_list ) { if( criteria hold for ae ) { SignalThread(ae->thread); } } return; }