/* ** weblib.c for assorted programs ** ** Copyright (C) 1995-1996, Andrew 'Dancer' Vesperman. All rights reserved. ** ** This file can be redistributed under the terms of the GNU General ** Public Licence. */ #include #include "module.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "weblib.h" FILE *ep; char last_info_url[455]; long ___CDECL _get_url_info(char *url, long *timep, long *sizep, char *type,int dofetch); #ifdef DEBUG void ___CDECL ierror(char *format,...) { va_list vargs; va_start(vargs,format); if(!ep) ep=fopen("error.log","w"); vfprintf(ep,format,vargs); fflush(ep); va_end(vargs); } #endif URL *___CDECL _parseURL(char *url) { static URL u; int x,y; browser->msg_status(STATUS_RESOLVING_HOST,0); u.port[0]='\0'; if(strlen(url)>1023) return NULL; x=0; y=0; while(url[x]&&url[x]!=':'&&url[x]!='/') gbuf[y++]=url[x++]; gbuf[y]='\0'; strcpy(u.request,gbuf); while(url[x]&&(url[x]==':'||url[x]=='/')) x++; if(!stricmp("news",u.request)) { /* special case URL */ /* news URL's are usually formatted as : */ strcpy(u.site,""); strcpy(u.path,url+x); /* fall through to port setting */ goto set_port; } y=0; while(url[x]&&url[x]!=':'&&url[x]!='/') gbuf[y++]=url[x++]; gbuf[y]='\0'; strcpy(u.site,gbuf); if(url[x]==':') { /* Got a port number */ x++; if(url[x]=='/') { /* Err, or perhaps not...*/ /* just fall through, I think */ } else { y=0; while(url[x]&&url[x]!='/') gbuf[y++]=url[x++]; gbuf[y]='\0'; strcpy(u.port,gbuf); } } if(!url[x]) { /* No path */ u.path[0]='/'; u.site[0]='\0'; } else strcpy(u.path,url+x); set_port: if(!u.port[0]) { if(!stricmp("http",u.request)) strcpy(u.port,"80"); else if(!stricmp("gopher",u.request)) strcpy(u.port,"79"); else if(!stricmp("ftp",u.request)) strcpy(u.port,"21"); else if(!stricmp("news",u.request)) strcpy(u.port,"119"); else if(!stricmp("wais",u.request)) strcpy(u.port,"210"); } return &u; } char *http_proxy(char *s) { if(!s) return getenv("http_proxy"); if(no_proxy(s)) return NULL; #ifdef DEBUG ierror("%s<0&&l2>0) { #ifdef DEBUG ierror("compare %c<->%c\n",s1[l1],s2[l2]); #endif if(toupper(s1[l1])!=toupper(s2[l2])) return 1; l1--; l2--; } #ifdef DEBUG ierror("compare %c<->%c\n",s1[l1],s2[l2]); #endif if(toupper(s1[l1])!=toupper(s2[l2])) return 1; return(0); } int no_proxy(char *s) { char sbuf[1024]; FILE *fh; int sanity=0; char *t; /* If the file 'no.proxy' exists, then override proxy use */ fh=fopen("no.proxy","r"); if(fh) { fclose(fh); #ifdef DEBUG ierror("Proxy overridden by no.proxy file\n"); #endif return(1); } /* If the environment variable no_proxy is not defined then we will always use a proxy */ if(!getenv("no_proxy")) { #ifdef DEBUG ierror("No no_proxy variable defined\n"); #endif return 0; } /* no_proxy is defined. Step through the list and try to match it against the supplied site. If we find a match then we do not proxy requests for this site */ strcpy(gbuf,getenv("no_proxy")); strcpy(sbuf,s); strcat(gbuf,","); t=strtok(gbuf,",;:"); if(!t) { #ifdef DEBUG ierror("Proxy list empty\n"); #endif return 0; } #ifdef DEBUG ierror("searching proxy list\n"); #endif do { #ifdef DEBUG ierror("no_proxy check: %s\n",t); #endif if(++sanity>50) { #ifdef DEBUG ierror("Sanity test aborted proxy check\n"); #endif return 1; } if(strlen(t)==0) continue; if(!rev_strcmp(t,sbuf)) { #ifdef DEBUG ierror("Do not proxy for this site: %s\n",s); #endif return 1; } } while(t=strtok(NULL,",;:")); #ifdef DEBUG ierror("Access Proxy for this site: %s\n",s); #endif return 0; } char *redirection(char *n) { FILE *fp; fp=fopen(n,"r"); if(!fp) return NULL; if(!fread(gbuf,6,1,fp)) return NULL; gbuf[6]='\0'; if(!stricmp("",gbuf)) { /* check document */ while(!feof(fp)) { fgets(gbuf,READ_SIZE,fp); if(!stricmp("Redirection",gbuf)) { while(!feof(fp)) { fgets(gbuf,READ_SIZE,fp); if(!strnicmp("",gbuf,7)) { fclose(fp); return(NULL); } } } fclose(fp); return(NULL); } URL *___CDECL parseURL(char *url) { URL *u; u=_parseURL(url); if(!stricmp("http",u->request)) { if(http_proxy(u->site)) { u=_parseURL(http_proxy(NULL)); strcpy(u->path,url); } } else if(!stricmp("gopher",u->request)) if(gopher_proxy(u->site)) { u=_parseURL(gopher_proxy(NULL)); strcpy(u->path,url); } else if(!stricmp("ftp",u->request)) if(ftp_proxy(u->site)) { u=_parseURL(ftp_proxy(NULL)); strcpy(u->path,url); } else if(!stricmp("wais",u->request)) if(ftp_proxy(u->site)) { u=_parseURL(wais_proxy(NULL)); strcpy(u->path,url); } else if(!stricmp("news",u->request)) if(ftp_proxy(u->site)) { u=_parseURL(news_proxy(NULL)); strcpy(u->path,url); } return u; } /* ** Open a socket to the specified service. */ int OpenConnection(char *host, char *service) { char **ap; char *fakelist[2]; register int i; struct servent *sp; struct servent s9; struct hostent *hp; struct hostent fakehp; struct in_addr quadaddr; struct sockaddr_in server; /* if(service[0]>='0'&&service[0]<='9') { if ((sp = getservbyname("http", "tcp")) == NULL) { #ifdef DEBUG ierror("Unknown service port %s\n",service); #endif return -1; } */ sp=&s9; sp->s_port=atoi(service); /* } else if ((sp = getservbyname(service, "tcp")) == NULL) { #ifdef DEBUG ierror("Unknown service name %s\n",service); #endif return -1; } */ /* Get the host's address. */ quadaddr.s_addr = inet_addr(host); if (quadaddr.s_addr != (unsigned long)-1) { /* Host was specified as a dotted-quad internet address. Fill in * the parts of the hostent struct that we need. */ fakehp.h_length = sizeof quadaddr; fakehp.h_addrtype = AF_INET; hp = &fakehp; fakelist[0] = (char *)&quadaddr; fakelist[1] = NULL; ap = fakelist; } else if ((hp = gethostbyname(host)) != NULL) { /* Symbolic host name. */ #if defined(h_addr) ap = hp->h_addr_list; #else /* Fake up an address list for old systems. */ fakelist[0] = (char *)hp->h_addr; fakelist[1] = NULL; ap = fakelist; #endif /* defined(h_addr) */ } else { #ifdef DEBUG ierror("Unknown host %s\n",host); #endif return -1; } browser->msg_status(STATUS_CONNECTING_HOST,0); /* Set up the socket address. */ (void)memset((char *)&server, 0, sizeof server); server.sin_family = hp->h_addrtype; server.sin_port = sp->s_port; /* Loop through the address list, trying to connect. */ for (; ap && *ap; ap++) { /* Make a socket and try to connect. */ if ((i = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) break; (void)memcpy((char *)&server.sin_addr, (char *)*ap, (int)hp->h_length); if (connect(i, (struct sockaddr *)&server, sizeof server) == 0) return i; (void)close(i); } #ifdef DEBUG ierror("Can't connect\n"); #endif return -1; } long readline(int zeroit,int s,char *buf,int limit) { char b; long c=0; int r; static long bcount; int timeout; fd_set rfds; struct timeval tv; if(zeroit) bcount=0; while(++cmsg_status(STATUS_WAITING_RESPONSE,timeout); write(s,"\n",1); /* poke it */ ++timeout; #ifdef DEBUG ierror("Timeout in readline() %d\n",timeout); #endif } else break; if(timeout>=10) { shutdown(s,2); buf[0]='\0'; return -1; } } r=read(s,&b,1); if(r!=1) return -1; if(b=='\r') goto ignore; *buf++=b; *buf='\0'; if(b=='\n') { browser->msg_status(STATUS_RECEIVING_DATA,bcount+=(c-1)); return c; } } return c; } /* ** Loop until the entire buffer is written. */ int xwrite(int fd, char *p, long i) { register long count; for ( ; i > 0; p += count, i -= count) if ((count = write(fd, p, i)) < 0) return -1; return 0; } static char formbuf[4096]; int xwritef(int fd,char *format,...) { va_list vargs; va_start(vargs,format); vsprintf(formbuf,format,vargs); va_end(vargs); return xwrite(fd,formbuf,strlen(formbuf)); } long ___CDECL _get_url(char *url, char *filename,char *kind) { URL *u; int s,timeout; FILE *t; char *rbb; fd_set rfds; struct timeval tv; long bcount=0; char rbuf[250]; long sz; int primitive=0,got_redirect=0,no_cache=0; if(stricmp(url,last_info_url)) { no_cache=1; } #ifdef DEBUG ierror("parsing url\n"); #endif rbb=rbuf; u=parseURL(url); if(!u) { browser->msg_error(EBADRQ); return EBADRQ; } #ifdef DEBUG ierror("URL Parsed. Opening connection.\n"); ierror("REQ : %s\n",u->request); ierror("PATH: %s\n",u->path); ierror("SITE: %s\n",u->site); ierror("PORT: %s\n",u->port); #endif s=OpenConnection(u->site,u->port); if(s==-1) { browser->msg_error(EPTHNF); return EPTHNF; } #ifdef DEBUG ierror("Connection opened\n"); #endif browser->msg_status(STATUS_SENDING_REQUEST,0); if(xwritef(s,"%s %s HTML/1.0\nUser-Agent: CAB/?.?? CAB-for-MiNT Overlay/%s\n\n\n",kind,u->path,version)) { shutdown(s,2); close(s); return EWRITF; } #ifdef DEBUG ierror("Sent %s.\n",kind); #endif if(no_cache) { #if 0 sz=write(s,"Pragma: no-cache\r\n",18); if(sz<1||sz>0x1000) { shutdown(s,2); close(s); return EWRITF; } #endif } browser->msg_status(STATUS_WAITING_RESPONSE,0); #ifdef DEBUG ierror("Unlink\n"); #endif Fchmod(filename,0x100|0x80|0x20|0x10|0x4|0x2); #ifdef DEBUG if(Fdelete(filename)) ierror("Unlink failed\n"); ierror("Open: %s\n",filename); #else Fdelete(filename); #endif t=fopen("u:\\tmp\\cabinfo","w"); #ifdef DEBUG ierror("opened file\n"); #endif if(!t) { #ifdef DEBUG ierror("Bad handle. Killing transaction.\n"); #endif shutdown(s,2); close(s); return EIHNDL; } #ifdef DEBUG ierror("Opened successfully\n"); #endif if(readline(1,s,gbuf,READ_SIZE)>1&&gbuf[0]) { if(strnicmp("HTTP/1.",gbuf,7)) { /* Eeek! Server is HTTP/0.9 */ primitive=1; } else { char *tmp; tmp=strchr(gbuf,' '); if(!tmp) { #ifdef DEBUG ierror("Malformed response line\n"); #endif shutdown(s,2); close(s); fclose(t); return EPLFMT; } ++tmp; if(*tmp=='4'||*tmp=='5'||*tmp=='1') { #ifdef DEBUG ierror("Got a failure code %c%c%c.\n",*tmp,*(tmp+1),*(tmp+2)); #endif shutdown(s,2); close(s); fclose(t); if(*tmp=='5') return EBADRQ; return EACCDN; } if(*tmp=='3') { /* Some kind of redirection */ got_redirect=1; } } if(primitive&&!stricmp("HEAD",kind)) { shutdown(s,2); close(s); return EBADRQ; } } else { #ifdef DEBUG ierror("Fatal error reading first response line\n"); #endif shutdown(s,2); close(s); return EREADF; } if(!stricmp("GET",kind)) while(readline(0,s,gbuf,READ_SIZE)>1&&gbuf[0]) { gbuf[strlen(gbuf)-1]='\0'; fprintf(t,"%s\n",gbuf); if(got_redirect&&!strnicmp("Location:",gbuf,9)) { char ubuf[250]; sscanf(gbuf,"Location: %s",ubuf); #ifdef DEBUG ierror("Attempting redirection to %s\n",ubuf); #endif shutdown(s,2); close(s); fclose(t); if(!browser->new_url(ubuf,&rbb)) { return get_url(ubuf,rbb); } return 0; } } fclose(t); if(strcmp("HEAD",kind)) _get_url_info(url,(long *)gbuf+10,(long *)gbuf+20,gbuf+40,0); t=fopen(filename,"wb"); if(!t) { #ifdef DEBUG ierror("Couldn't open filename supplied by CAB\n"); #endif shutdown(s,2); close(s); return EFILNF; } while(1) { timeout=0; while(1) { FD_ZERO(&rfds); FD_SET(s,&rfds); tv.tv_sec=3; tv.tv_usec=0; if(!select(1,&rfds,NULL,NULL,&tv)) { browser->msg_status(STATUS_WAITING_RESPONSE,timeout); ++timeout; write(s,"\n",1); #ifdef DEBUG ierror("Timeout %d\n",timeout); #endif } else break; if(timeout>=10) { fclose(t); shutdown(s,2); close(s); return EREADF; } } sz=read(s,gbuf,READ_SIZE); #ifdef DEBUG ierror("read %ld\n",sz); #endif if(sz<1) break; if(sz==-1||sz>READ_SIZE) { shutdown(s,2); fclose(t); close(s); return EREADF; } sz=fwrite(gbuf,1,sz,t); if(sz<1||sz>READ_SIZE) { shutdown(s,2); fclose(t); close(s); return EWRITF; } #ifdef DEBUG ierror("write %ld\n",sz); #endif bcount+=sz; browser->msg_status(STATUS_RECEIVING_DATA,bcount); } fclose(t); browser->msg_status(STATUS_RECEIVING_DATA,bcount); shutdown(s,2); close(s); if(!stricmp("GET",kind)) { /* check for redirections */ if(redirection(filename)) if(!browser->new_url(gbuf,&rbb)) { char ubuf[250]; strcpy(ubuf,gbuf); return get_url(ubuf,rbb); } return 0; } #ifdef DEBUG ierror("Return 0"); #endif return 0; } long make_unix_time(char *s) { struct tm time; int i; char day[128]; char month[20]; char *monthtab[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; char *n; if(s[3]!=' '&&s[3]!=',') { n=s; while(*n) { if(*n=='-'||*n==':') *n=' '; *n++; } time.tm_mon=0; sscanf(s,"%s %d %s %d %d %d %d GMT",day,&time.tm_mday, month, &time.tm_year, &time.tm_hour, &time.tm_min,&time.tm_sec); for(i=0;i<12;i++) { if(!stricmp(month,monthtab[i])) time.tm_mon=i; } time.tm_isdst=0; /* daylight saving is never in effect in GMT */ return mktime(&time); } else if(s[3]==',') { n=s; while(*n) { if(*n=='-'||*n==':') *n=' '; *n++; } time.tm_mon=0; sscanf(s,"%s %d %s %d %d %d %d GMT",day,&time.tm_mday, month, &time.tm_year, &time.tm_hour, &time.tm_min,&time.tm_sec); time.tm_year-=1900; for(i=0;i<12;i++) { if(!stricmp(month,monthtab[i])) time.tm_mon=i; } time.tm_isdst=0; /* daylight saving is never in effect in GMT */ return mktime(&time); } n=s; while(*n) { if(*n=='-'||*n==':') *n=' '; *n++; } time.tm_mon=0; sscanf(s,"%s %s %d %d %d %d %d",day,month,&time.tm_mday,&time.tm_hour,&time.tm_min,&time.tm_sec,&time.tm_year); time.tm_year-=1900; for(i=0;i<12;i++) { if(!stricmp(month,monthtab[i])) time.tm_mon=i; } time.tm_isdst=0; /* daylight saving is never in effect in GMT */ return mktime(&time); } #if KEEPINFO static long last_sizep[KEEPINFO],last_timep[KEEPINFO]; static char last_type[KEEPINFO][255],last_url[KEEPINFO][1024]; static int keepinit=0; #endif long ___CDECL _get_url_info(char *url, long *timep, long *sizep, char *type,int dofetch) { int r; char minibuf[250]; char dummy[128]; FILE *fp; #if KEEPINFO #ifdef DEBUG ierror("Doing funky cache thangs\n"); #endif if(!keepinit) { keepinit=1; for(r=0;r0;r--) { last_timep[r]=last_timep[r-1]; last_sizep[r]=last_sizep[r-1]; strcpy(last_type[r],last_type[r-1]); strcpy(last_url[r],last_url[r-1]); } strcpy(last_url[0],url); last_timep[0]=*timep; last_sizep[0]=*sizep; strcpy(last_type[0],type); #endif return 0; }