static void mainloop(struct gopherus *g) { int exitflag; int bufferlen; for (;;) { struct url *url = &(g->history->url); /* a shortcut */ if ((url->itemtype == GOPHER_ITEM_FILE) || (url->itemtype == GOPHER_ITEM_DIR) || (url->itemtype == GOPHER_ITEM_INDEX_SEARCH_SERVER) || (url->itemtype == GOPHER_ITEM_HTML)) { /* if it's a displayable item type... */ draw_urlbar(url, &g->cfg); if (g->history->cache == NULL) { /* reload the resource if not in cache already */ bufferlen = loadfile_buff(url, g->buf, buffersize, g->statusbar, NULL, &g->cfg); if (bufferlen < 0) { history_back(&g->history); continue; } else { history_cleanupcache(g->history); g->history->cache = malloc(bufferlen); if (g->history->cache == NULL) { sprintf(g->statusbar, "Out of memory!"); exitflag = 1; break; } if (bufferlen > 0) memcpy(g->history->cache, g->buf, bufferlen); g->history->cachesize = bufferlen; } } switch (url->itemtype) { case GOPHER_ITEM_FILE: /* text file */ exitflag = display_text(g, TXT_FORMAT_RAW); break; case GOPHER_ITEM_HTML: /* html file */ exitflag = display_text(g, TXT_FORMAT_HTM); break; case GOPHER_ITEM_DIR: /* menu */ case GOPHER_ITEM_INDEX_SEARCH_SERVER: /* query result (also a menu) */ exitflag = display_menu(g); break; default: set_statusbar(g->statusbar, "Fatal error: got an unhandled itemtype!"); exitflag = DISPLAY_ORDER_QUIT; break; } if (exitflag == DISPLAY_ORDER_BACK) { history_back(&(g->history)); } else if (exitflag == DISPLAY_ORDER_REFR) { free(g->history->cache); g->history->cache = NULL; g->history->cachesize = 0; g->history->displaymemory[0] = -1; g->history->displaymemory[1] = -1; } else if (exitflag == DISPLAY_ORDER_QUIT) { break; } } else { /* the itemtype is not one of the internally displayable types -> ask to download it */ char filename[64] = {0}; static const char prompt[] = "Download as: "; char *lastslash = strrchr(url->selector, '/'); set_statusbar(filename, ""); /* make sure to clear out the status bar */ draw_statusbar(filename, &g->cfg); ui_cputs(prompt, 0x70, 0, ui_rows - 1); if (lastslash) strncpy(filename, lastslash + 1, sizeof filename - 1); if (editstring(filename, 63, ui_cols - (sizeof prompt - 1), sizeof prompt - 1, ui_rows - 1, 0x70, NULL) != 0) { loadfile_buff(url, g->buf, buffersize, g->statusbar, filename, &g->cfg); } history_back(&(g->history)); } } }
void vendor_buy_fish(int fd, gamestate_t* state, void *data, const char* input) { int n = atoi(input); state->gold -= 2*n; draw_statusbar(fd,state); show_multiline_text(fd,vendor_fish,vendor.npcdesc); }
/* downloads a gopher or http resource and write it to a file or a memory buffer. if *filename is not NULL, the resource will be written in the file (but a valid *buffer is still required) */ static long loadfile_buff(const struct url *url, char *buffer, long buffer_max, char *statusbar, char *filename, struct gopherusconfig *cfg) { unsigned long int ipaddr; long reslength, byteread, fdlen = 0; char statusmsg[128]; FILE *fd = NULL; int headersdone = 0; /* used notably for HTTP, to localize the end of headers */ time_t lastactivity, curtime; if (url->host[0] == '#') { /* embedded start page */ reslength = load_embedded_page(buffer, url->host + 1); /* open file, if downloading to a file */ if (filename != NULL) { fd = fopen(filename, "rb"); /* try to open for read - this should fail */ if (fd != NULL) { set_statusbar(statusbar, "!File already exists! Operation aborted."); fclose(fd); return -1; } fd = fopen(filename, "wb"); /* now open for write - this will create the file */ if (fd == NULL) { /* this should not fail */ set_statusbar(statusbar, "!Error: could not create the file on disk!"); fclose(fd); return -1; } fwrite(buffer, 1, reslength, fd); fclose(fd); } return reslength; } ipaddr = dnscache_ask(url->host); if (ipaddr == 0) { sprintf(statusmsg, "Resolving '%s'...", url->host); draw_statusbar(statusmsg, cfg); ipaddr = net_dnsresolve(url->host); if (ipaddr == 0) { set_statusbar(statusbar, "!DNS resolution failed!"); return -1; } dnscache_add(url->host, ipaddr); } sprintf(statusmsg, "Connecting to %d.%d.%d.%d...", (int)(ipaddr >> 24) & 0xFF, (int)(ipaddr >> 16) & 0xFF, (int)(ipaddr >> 8) & 0xFF, (int)(ipaddr & 0xFF)); draw_statusbar(statusmsg, cfg); if (net_connect(ipaddr, url->port) != 0) { set_statusbar(statusbar, "!Connection error!"); return -1; } if (url->protocol == PARSEURL_PROTO_HTTP) { /* http */ sprintf(buffer, "GET /%s HTTP/1.0\r\nHOST: %s\r\nUSER-AGENT: Gopherus v" VERSION "\r\n\r\n", url->selector, url->host); } else { /* gopher */ sprintf(buffer, "%s\r\n", url->selector); } if (net_send(buffer, strlen(buffer)) != (int)strlen(buffer)) { set_statusbar(statusbar, "!send() error!"); net_close(); return -1; } /* prepare timers */ lastactivity = time(NULL); curtime = lastactivity; /* open file, if downloading to a file */ if (filename != NULL) { fd = fopen(filename, "rb"); /* try to open for read - this should fail */ if (fd != NULL) { set_statusbar(statusbar, "!File already exists! Operation aborted."); fclose(fd); net_abort(); return -1; } fd = fopen(filename, "wb"); /* now open for write - this will create the file */ if (fd == NULL) { /* this should not fail */ set_statusbar(statusbar, "!Error: could not create the file on disk!"); fclose(fd); net_abort(); return -1; } } /* receive answer */ reslength = 0; for (;;) { if (buffer_max + fdlen - reslength < 1) { /* too much data! */ set_statusbar(statusbar, "!Error: Server's answer is too long!"); reslength = -1; break; } byteread = net_recv(buffer + (reslength - fdlen), buffer_max + fdlen - reslength); curtime = time(NULL); if (byteread < 0) break; /* end of connection */ if (is_int_pending()) { set_statusbar(statusbar, "Connection aborted by the user."); reslength = -1; break; } if (byteread > 0) { lastactivity = curtime; reslength += byteread; /* if protocol is http, ignore headers */ if ((url->protocol == PARSEURL_PROTO_HTTP) && (headersdone == 0)) { int i; for (i = 0; i < reslength - 2; i++) { if (buffer[i] == '\n') { if (buffer[i + 1] == '\r') i++; /* skip CR if following */ if (buffer[i + 1] == '\n') { i += 2; headersdone = reslength; for (reslength = 0; i < headersdone; i++) buffer[reslength++] = buffer[i]; break; } } } } else { sprintf(statusmsg, "Downloading... [%ld bytes]", reslength); set_statusbar(statusbar, statusmsg); draw_statusbar(statusbar, cfg); if ((fd != NULL) && (reslength - fdlen > 4096)) { /* if downloading to file, write stuff to disk */ int writeres = fwrite(buffer, 1, reslength - fdlen, fd); if (writeres < 0) writeres = 0; fdlen += writeres; } } } else { if (curtime - lastactivity > 2) { if (curtime - lastactivity > 20) { /* TIMEOUT! */ set_statusbar(statusbar, "!Timeout while waiting for data!"); reslength = -1; break; } else { usleep(250000); /* give the cpu some time up (250ms), the transfer is really slow */ } } } } if (reslength >= 0) { statusmsg[0] = 0; draw_statusbar(statusmsg, cfg); net_close(); } else { net_abort(); } if (fd != NULL) { /* finish the buffer */ char tmpmsg[80]; if (reslength - fdlen > 0) { /* if anything left in the buffer, write it now */ fdlen += fwrite(buffer, 1, reslength - fdlen, fd); } fclose(fd); sprintf(tmpmsg, "Saved %ld bytes on disk", fdlen); set_statusbar(statusbar, tmpmsg); } return reslength; }