
// GNUpyright (G)1999 Arachne Labs

// Check http://www.arachne.cz/ for more details.

// patched by PASKY - now just -DRFROM_CONSOLE and no exit(-1)'ll more happens
// and one more patch by PASKY - *partial* fix of broken name-search in query string

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/stat.h>

#define VER "0.66"

#define loop while(1)

#define MAXCGILEN 2048
#define MAXPOSTLEN 1000000l
#define TEMP "/tmp/cgi.tmp"
#define SENDMAIL "/usr/sbin/sendmail"

//-----------------------------------------------------------------------
// Get querystring, either from stdion or from $QUERY_STRING
//-----------------------------------------------------------------------

char *inbuf=NULL;

char *getqs(void)
{
 char *a=getenv("REQUEST_METHOD");

 if(!a)
#ifndef RFROM_CONSOLE
  exit(-1);
#else
 return NULL;
#endif

 if(!strcmp(a,"POST"))
 {
  //puts("!result of post operation<BR>");
  if(!inbuf)
  {
   long k=0,l;
   a=getenv("CONTENT_TYPE");
   if(*a && strcmp(a,"application/x-www-form-urlencoded"))
    return NULL;
   //puts("!x-www-form-urlencoded<BR>");
   a=getenv("CONTENT_LENGTH");
   l=atol(a);
   //printf("content-legth=%ld<BR>",l);
   if(l>MAXPOSTLEN)
   {
    printf("<H3>Form error - too many bytes sent. Will be tructed to %ld bytes.</H3>\n",MAXPOSTLEN);
    l=MAXPOSTLEN;
   }
   inbuf=malloc(l+1);
   if(!inbuf)
    exit(-1);
   //printf("allocated=%ld<BR>",l);
   while(k<l)
   {
    inbuf[k++]=getchar();
   }
   inbuf[l]='\0';
//   puts(inbuf);
  }
  return inbuf;
 }
 else
  return getenv("QUERY_STRING");
}

//-----------------------------------------------------------------------
// This function is here to analyse CGI query string - *value is output
// getvar is wrapper for getnvar.
//-----------------------------------------------------------------------

int getvar(char *name,char *value)
{
 return (getnvar(name,value,MAXCGILEN));
}

int getnvar(char *name,char *value, int charlimit)
{
 char pom[8]="0xXX";
 int i,len=0;
 char *qs=getqs();
 char *ptr;

 if(!qs)
  return 0;

 ptr=qs;
cgiznovu:
 ptr=strstr(ptr,name);
 *value='\0';
 if(ptr)
 {
  ptr+=strlen(name);  
  if(!*ptr)
   return 0;
  else
  if(*ptr=='=')
   ptr++; else if (*ptr!='&') goto cgiznovu;
  while(*ptr && *ptr!='&' && len<charlimit-1)
  {
   if(*ptr=='+')
   {
    *value=' ';
    ptr++;
   }
   else if(*ptr=='%')
   {
    strncpy(&pom[2],&ptr[1],2);
    sscanf(pom,"%x",&i);
    *value=(char)i;
    ptr+=3;
   }
   else
   {
    *value=*ptr;
    ptr++;
   }
   value++;
   len++;
  }//loop
  *value='\0';
  return 1;
 }
 else
  return 0;
}

//-----------------------------------------------------------------------
// time stamp - this should prevent people from misusing CGI script
//-----------------------------------------------------------------------

int timecheck(char *filename,long seconds)
{
 FILE *oldf,*newf;
 char *remote=getenv("REMOTE_HOST");
 int i;
 char str[128];
 long cas=time(NULL);
 int rv=1;
 char add=1;

 if(!remote)
  remote=getenv("REMOTE_ADDR");
 if(!remote)
  return;
 
 i=strlen(remote); 
 unlink(TEMP);
 newf=fopen(TEMP,"w");
 if(!newf)
 {
  puts("<H3>Server error (?) - please report error to the webmaster...</H3>");
  return 1;
 }

 oldf=fopen(filename,"r");
 if(oldf)
 {
  loop
  {
   fgets(str,120,oldf);
   if(feof(oldf))
    break;
 
   if(!strncmp(remote,str,i))
   {
    long oldcas=atol(&str[i+1]);
 
    add=0;
    if(cas-oldcas>seconds)
     fprintf(newf,"%s %ld\n",remote,cas);
    else
    {
     fprintf(newf,"%s %ld\n",remote,oldcas);
     rv=0;
    }
   }
   else
    fputs(str,newf);
  }//loop
  fclose(oldf);
 }
 if(add)
  fprintf(newf,"%s %ld\n",remote,cas);

 fclose(newf);

 unlink(filename);
 rename(TEMP,filename);
 return rv;
}

//-----------------------------------------------------------------------
// file locking - exclusive access to certain critical areas
//-----------------------------------------------------------------------

int CGIlock(char *fname)
{
 int f=open(fname,O_RDONLY);
 if(f<0)
 {
  f=open(fname,O_WRONLY|O_CREAT,S_IWRITE|S_IREAD);
  if(f<0)
   return -1;
 }
 while(flock(f,LOCK_EX)==-1)
  sleep(1);
 return f;
}

void CGIunlock(int f)
{
 if(f<0)
  return;
 flock(f,LOCK_UN);
 close(f);
}

//-----------------------------------------------------------------------
// simple sendmail without writing temporary file
//-----------------------------------------------------------------------

void sendmail(char *from, char *addr, char *subj, char *msg)
{
 int vidle,roura[2],raw=0;
 char *subjcmd="\0";

 if(!subj)
 {
  subj="\0";
  raw=1;
 }
 else if(!(*subj))
 {
  subj="\0";
 }
 else
  subjcmd="\nSubject: ";
  
 if(pipe(roura)<0 || !addr)
  exit(-1); 
 
 vidle=fork();
 if(vidle)
 {
   char *buf=malloc(strlen(from)+strlen(addr)+strlen(subj)+strlen(msg)+128);
   if(!buf)
    exit(-1);

   close(roura[0]);
   if(!raw)
   {
    sprintf(buf,"From: %s\nTo: %s%s%s\n\n%s\n",from,addr,subjcmd,subj,msg);
    write(roura[1],buf,strlen(buf));
   }
   else
    write(roura[1],msg,strlen(msg));
   free(buf);
   exit(0);
 } 
 else
 {
   close(0);
   close(roura[1]);
   dup(roura[0]);
   vidle=fork();
   if(vidle<0)
    exit(-1);
   else if(vidle>0)
    execlp(SENDMAIL,SENDMAIL,addr,NULL);
 }
}

//-----------------------------------------------------------------------
// heh ?
//-----------------------------------------------------------------------

void HTTPheader(char *mime)
{
 printf("Content-type: %s\r\n\r\n",mime);
}

//-----------------------------------------------------------------------
// huh...
//-----------------------------------------------------------------------
void HTMLheader(char *title, char *body)
{
 printf("<HTML>\r\n<HEAD>\r\n");
 printf("<TITLE>%s</TITLE>\r\n",title);
 printf("</HEAD>\r\n\r\n<BODY%s>\r\n",body);
}

void HTMLlink(char *str)
{
 printf("<A HREF=\"%s\">%s</A>\r\n",str,str);
}

void HTMLtagH(char *str,int n)
{
 printf("<H%1d>%s</H%1d>\r\n",n,str,n);
}

void HTMLhr(void)
{
 puts("<HR>");
}

//-----------------------------------------------------------------------
// Open <FORM> recursive calling this CGI (very common in CGI programming....)
//-----------------------------------------------------------------------

void HTMLrecursiveFORM(char *method)
{
 printf("<FORM ACTION=\"http://%s%s\" METHOD=%s>\r\n",getenv("SERVER_NAME"),getenv("SCRIPT_NAME"),method);
}

//-----------------------------------------------------------------------
// Recursive INPUT item
//-----------------------------------------------------------------------

void HTMLrecursiveINPUT(char *name,char *defaultvalue,int size)
{
 char str[MAXCGILEN];

 if(!getvar(name,str))
 {
  if(defaultvalue)
   strcpy(str,defaultvalue);
  else
   str[0]='\0';
 }
 printf("<INPUT TYPE=TEXT NAME=\"%s\" SIZE=%d VALUE=\"%s\">\r\n",name,size,str);
}

void HTMLrecursivePASSWORD(char *name,char *defaultvalue,int size)
{
 char str[MAXCGILEN];

 if(!getvar(name,str))
 {
  if(defaultvalue)
   strcpy(str,defaultvalue);
  else
   str[0]='\0';
 }
 printf("<INPUT TYPE=PASSWORD NAME=\"%s\" SIZE=%d VALUE=\"%s\">\r\n",name,size,str);
}


void HTMLrecursiveTEXTAREA(char *name,char *defaultvalue,int sizex, int sizey)
{
 char str[MAXCGILEN];
 if(!getvar(name,str))
 {
  if(defaultvalue)
   strcpy(str,defaultvalue);
  else
   str[0]='\0';
 }
 printf("<TEXTAREA NAME=\"%s\" COLS=%d ROWS=%d>%s</TEXTAREA>\r\n",name,sizex,sizey,str);
}

//-----------------------------------------------------------------------
// hehehehe... ;-)
//-----------------------------------------------------------------------

void HTMLfooter(void)
{
 printf("\r\n<HR><I>Powered by <B>&lt;cgi.h&gt;</B> version %s. GNUpyright (G) 1999 by\
 <A HREF=\"http://www.arachne.cz/\">Arachne Labs</A></I>\r\n",VER);
 printf("\r\n\r\n</BODY>\r\n</HTML>\r\n");
 if(inbuf)
  free(inbuf);
}
