/*hingo@multi.fi (c) JUNE 1997, ver 0.1 */
/*This is a cgi-program that will use lynx to get a document and then take a 
quote from it as specified in the file CONFIGFILE.
The program assumes lines shorter than 1000 characters in CONFIGFILE*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>

#define TITLE "Quote.cgi 0.2 by hingo@multi.fi, 1997."
/*define the name of the file with configurations*/
#define CONFIGFILE "quoterc"
/*define the variables used in the config file*/
#define URL "URL="
#define LINKS "LINKS="
#define BEGIN "BEGIN="
#define END "END="
#define HEADER "HEADER="
#define FROM "FROM="

#define TEMPFILE "quote.tmp"

/*define different errortypes, and messages*/
#define BUGREPORTTO "hingo@multi.fi" 
#define CONFERR 1
#define LYNXERR 2
#define HTMLERR 3
/******************************************/
#define TRUE 1
#define FALSE 0

void fatal(int errtype, char * string)
{
  printf("<H1>Quote.cgi error!</H1>\n");

  if(errtype==CONFERR)
    {
      printf("<H3>An error occured while trying to read the ");
      printf("configuration file. <BR> \n");
      printf("The file '%s'", CONFIGFILE);
      printf("' may be of wrong format or missing. </H3>\n");
    }
  if(errtype==LYNXERR)
    {
      printf("<H3>An error occured while trying to use lynx ");
      printf("to get the page %s. <BR> \n", string);
      printf("Lynx may not be properly installed on this system ");
      printf("or the homepage was unreachable </H3>\n");
    }
  if(errtype==HTMLERR)  
    {
      printf("<H3>An error occured while processing the HTML-code from ");
      printf("<A HREF='%s'> %s </A>.<BR> \n", string,string);
      printf("Probably the page and the configurationfiles don't match.");
    }  
    
  printf("<P>Bugreports to: <A HREF='mailto:");
  printf(BUGREPORTTO);printf("'>");printf(BUGREPORTTO);printf("</A>");
  
  exit(errtype);
}
/*skip() is used to scroll a file until a line not beginning with a #
It also skips empty lines and lines beginning with a whitespace.
returns EOF if end of file is reached*/

int skip(FILE * fp)
{
  char ch=!EOF, dummy[1024];

  ch = fgetc(fp);
  while(ch==' ' || ch=='\n' || ch=='\r' || ch=='\t' || ch == '#')
    {
      if( ch == EOF)
        break;
      else
        fgets(dummy, 1023, fp);
    
    ch = fgetc(fp);
    }
  /*the last character taken was not a # so we'd better return it*/
  ungetc(ch, fp);

  return(ch);
}

void clear(char *str, int n)
{

  while( n > 0 )
    {
      n--;
      str[n]='\0';
    }
}

void clearend(char *str)
{
  if(!isgraph(str[strlen(str)-1]))
    {
      str[strlen(str)-1]='\0';
      clearend(str);
    }    
}

/*match() returns TRUE if the string matches the current position in 
the file or EOF is reached*/
int match(FILE * fp, char * str, int print)
{
  char ch =! '\n';
  
  ch=fgetc(fp);

  if(ch=='\n')
    {
      putchar(' ');
      do
        {
          ch=fgetc(fp);
        }while('\n' == ch);
    }

  if(ch==EOF)
    {
      ungetc(ch,fp);
      return(TRUE);
    }
  if(print==TRUE)
    fputc(ch, stdout);
  if((tolower(ch) == tolower(str[0]) || 
      (ch=='\'' && str[0]=='"') || (ch=='"' && str[0]=='\'')))
    {
      if(str[1]=='\0')
        return(TRUE);
      else 
        return(match(fp, &str[1], print));
    }
  else
    return(FALSE);
}

/* scrolls to a place matching the string in the file and stops after the
found string. Returns TRUE if found, FALSE if EOF was reached.*/
int scrollto(FILE * fp, char * str, int print)
{
  char ch=!EOF;
  
  while(!match(fp, str, print));

  ch=fgetc(fp);
  if(ch==EOF)
    return(FALSE);
  else
    {
      ungetc(ch, fp);
      return(TRUE);
    }
}


/*count(file, string) counts how many 'strings' there are in 'file'.
case insensitive*/

int count(FILE * fp, char * str)
{
  int n=0;

  while(scrollto(fp, str, FALSE)==TRUE)
    n++;
  return(n);
}

int copy(FILE * fp, char * str, char * target)
{
  char ch =! '\n';
  
  ch=fgetc(fp);

  if(ch==EOF)
    {
      ungetc(ch,fp);
      return(TRUE);
    }

  target[strlen(target)]=ch;

  if((tolower(ch) == tolower(str[0]) || 
      (ch=='\'' && str[0]=='"') || (ch=='"' && str[0]=='\'')))
    {
      if(str[1]=='\0')
        return(TRUE);
      else 
        return(copy(fp, &str[1], target));
    }
  else
    return(FALSE);
}

int copyto(FILE * fp, char * str, char * target)
{
  char ch=!EOF;
  
  while(!copy(fp, str, target));

  ch=fgetc(fp);
  if(ch==EOF)
    return(FALSE);
  else
    {
      ungetc(ch, fp);
      return(TRUE);
    }
}



void getconf(char * url, int * links, char * begin, char * end,
             char * from, char * header)
{
  FILE * fpconf;
  char buffer[1024]={'\0'};
  
  fpconf=fopen(CONFIGFILE, "r");
  if(fpconf==NULL) 
    fatal(CONFERR, NULL);
  
  if(skip(fpconf)==EOF)
    fatal(CONFERR, NULL);

  /*The first line of CONFIGFILE is the header to print*/
  if((!strncmp(buffer, HEADER, strlen(HEADER))) ||
    fgets(buffer, 1024, fpconf)==NULL)
    fatal(CONFERR, NULL);
  else
    strcpy(header, &buffer[strlen(HEADER)]);                    
  
  /*Scroll the CONFIGFILE until a line beginning with URL is found*/
  while(url[0]=='\0')
    {
      if(fgets(buffer, 1024, fpconf)==NULL)
        fatal(CONFERR, NULL);
      if(!strncmp(buffer, URL, strlen(URL)))
        strcpy(url, &buffer[strlen(URL)]);
    }
  
  /*Then read in the other variables*/
  if(skip(fpconf)!=EOF)
    {
      buffer[0]='#'; /* the URL cannot be defined to begin with a #*/
      while(strncmp(buffer, URL, strlen(URL)) && 
            fgets(buffer, 1023, fpconf) != NULL) 
        {   
          if(!strncmp(buffer, LINKS, strlen(LINKS)))
            *links = buffer[strlen(LINKS)] - '0';
          else if(!strncmp(buffer, BEGIN, strlen(BEGIN)))
            strcpy(begin, &buffer[strlen(BEGIN)]); 
          else if(!strncmp(buffer, END, strlen(END)))
            strcpy(end, &buffer[strlen(END)]); 
          else if(!strncmp(buffer, FROM, strlen(FROM)))
            strcpy(from, &buffer[strlen(FROM)]); 
          else
            fatal(CONFERR, NULL);
      
          if(skip(fpconf)==EOF)
            break;
        }  
    }        
  fclose(fpconf);
}   /*End, getconf()*/




int main(void)
{
  char url[257]={'\0'}, begin[32]="<P>", end[32]="<P>";  
  char from[1024]={'\0'}, header[1024]={'\0'}, buffer[1024]={'\0'};
  int links=0, n=0, m=0;
  time_t t;
  FILE * fp;

  srand(time(&t));
  printf("Content-type: text/html\n\n"); 
  
  /*Getting the configurations*/
  getconf(url, &links, begin, end, from, header);
  clearend(url); clearend(begin); clearend(end);

  /*Make the command string for lynx*/  
  sprintf(buffer, "lynx -source %s > %s", url, TEMPFILE);
  
  /*Then make lynx to get the first page*/
  if(system(buffer)==-1)
    fatal(LYNXERR, url);
  
  while(links > 0)
    {
      /*count the urls given in the document*/
      fp=fopen(TEMPFILE, "r");
      n=count(fp, "<A HREF=\"");
      if(n==0)
        {
	  printf("\n debugging info: error in 'links' -loop");
	  fatal(HTMLERR, url);
	}
      n= 1 + (double) n * (double) rand() / RAND_MAX;
      /*Start from the beginning of the file*/
      fclose(fp); fp=fopen(TEMPFILE, "r");

      /*Find the n:th url*/
      while(n > 0)
        {
          scrollto(fp, "<A HREF=\"", FALSE);
          n--;
        }

      clear(buffer, 1024);
      copyto(fp, "\"", buffer);
      /*remove the " from the end of buffer*/
      buffer[strlen(buffer) - 1]='\0';

      if(!strncmp(buffer, "http://", 7))
	strcpy(url, buffer);
      else
	strcat(url, buffer);
      clearend(url);

      fclose(fp);
      sprintf(buffer, "lynx -source %s > %s", url, TEMPFILE);
      if(system(buffer)==-1)
        fatal(LYNXERR, url);

      links--;
    }

  /*count the BEGIN-marks and draw one of them*/
  fp=fopen(TEMPFILE, "r");
  n=count(fp, begin);
  if(n == 0)
    fatal(HTMLERR, url);
  n= 1 + (double) n * (double) rand() / RAND_MAX;

  /*Start from the beginning of the file*/
  fclose(fp); fp=fopen(TEMPFILE, "r");

  /*let's catch the <title> from the beginning first*/
  scrollto(fp, "<TITLE>", FALSE);
  clear(buffer, 1024);
  copyto(fp, "</TITLE>", buffer);
  for(m=0; m<8; m++)
    buffer[strlen(buffer)-1]='\0';

  /*Find the n:th quote*/
  while(n > 0)
    {
      scrollto(fp, begin, FALSE);
      n--;
    }
  /*And print it.*/
  printf("\n<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY>\n", TITLE);
  printf("%s \n<HR> <H3> %s", header, begin);

  scrollto(fp, end, TRUE);
  
  printf("</H3>\n<BLOCKQUOTE><I>From: %s : %s<BR>\n" ,from,buffer);
  printf("<A HREF='%s'>%s</A>\n",url,url);
  printf("</I></BLOCKQUOTE></BODY></HTML>\n");

  fclose(fp);
  sprintf(buffer, "rm %s", TEMPFILE);
  system(buffer);

  return(0);
}
