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

#ifndef FALSE
#define TRUE (0==0)
#define FALSE (0!=0)
#endif

#define FIRSTQUOTE 1
#define LASTQUOTE 66788

/// #define FIRSTQUOTE 1
/// #define LASTQUOTE 1853

// #define FIRSTQUOTE 247208
// #define LASTQUOTE  249916

#define GRAB "/usr/bin/lynx -dump -source http://www.bartleby.com/66/%d/%d.html > /tmp/quote.%0d"
/// #define GRAB "/usr/bin/lynx -dump -source http://quotes.mist.ath.cx/specific.asp?id=%d > /tmp/quote.%0d"
// #define GRAB "/usr/bin/lynx -dump -source http://w2.xrefer.com/entry.jsp?xrefid=%0d\\&secid=.1.- > /tmp/quote.%0d"

#define AUTHORTAG    "ATTRIBUTION:</FONT></TD><TD VALIGN=\"top\">"
#define AUTHORENDTAG "</TD></TR>"
/// #define AUTHORTAG    "<span class=\"author\">"
/// #define AUTHORENDTAG "</span>"
// #define AUTHORTAG    "<title>xrefer - "
// #define AUTHORENDTAG "</title>"
/*
#define QUOTETAG     "<span class=\"intro\">"
#define QUOTETAG2    "<blockquote>"
#define QUOTEENDTAG  "<span class=\"sHdr\">"
*/
// #define QUOTETAG     "<span class=\"eBody\">"
// #define QUOTETAG2    "<blockquote>"
// #define QUOTEENDTAG  "<span class=\"sHead\">"
/// #define QUOTETAG     "<span class=\"quote\">"
/// #define QUOTETAG2    "<ZZZUNUSEDZZZ>"
/// #define QUOTEENDTAG  "</span>"
#define QUOTETAG     "QUOTATION:</FONT></TD><TD VALIGN=\"top\">"
#define QUOTETAG2    "<ZZZUNUSEDZZZ>"
#define QUOTEENDTAG  "</TD></TR>"

void systemf(char *s, int d)
{
  char temp[1024];
  /* Temp implementation until I can find va_args examples to copy */
  sprintf(temp, s, d % 100, d, d);
///  sprintf(temp, s, d, d, d);
  system(temp);
}

FILE *fopenf(char *s, int d, char *f)
{
  char temp[1024];
  sprintf(temp, s, d);
  return(fopen(temp, f));
}

int irand(int max)
{
  /* random int between 0 (inclusive) and max (exclusive) */
  long l;
  if (max < 0) max = 0 - max;
  if (max == 0) return(0);
  l = random();
  if (l < 0L) l = 0L - l;
  l = l % (long)max;
  if (l >= (long)max) l = 0L;
  return((int)l);
}

int main(int argc, char **argv)
{
#define swap(ii, jj) {int tmp = (ii); ii = (jj); jj = tmp;}
#define translate(s) {int i; for (i = 0; i < strlen(s); i++) s[i] = trans[s[i]];}
  char line[16000];
  char Attribution[16000];
  char Quote[16000];
  char trans[256];
  FILE *qfile;
  char *s, *t, *u;
  int goodmap;
  int quotno;
  int c;
  int i;
  int tries;

  /* Generate random number within range of Oxford Dictionary of Quotations
     entries at xrefer.com */

  /* To generate a quote of the day, rather than random quotes,
     initialise the random seed using the date rather than the time */

  srandom((unsigned int)((unsigned int)time(NULL)/(15UL*60UL))); // change every 15 mins

  /* Set up a random crypto mapping */
  for (i = 0; i < 256; i++) {
    trans[i] = i;
  }
  for (i = 'a'; i < 'z'; i++) {
    c = irand('z'-i-1);
    swap(trans[i], trans[i+c]);
  }

  /* elimate self-mapping */
  for (i = 'a'; i < 'z'; i++) {
    if (trans[i] == i) {
      swap(trans[i], trans[i+1]);
    }
  }
  if ((trans['y'] == 'z') && (trans['z'] == 'y')) swap(trans['y'], trans['z']);
  if (trans['y'] == 'y') {
    c = irand('p'-'a');
    swap(trans['y'], trans['a'+c]);
  }
  if (trans['z'] == 'z') {
    c = irand('k'-'a');
    swap(trans['z'], trans['a'+c]);
  }

  /*( Make uppercase match lowercase */
  for (i = 'a'; i < 'z'+1; i++) {
    trans[i-'a'+'A'] = trans[i];
  }


  for (tries = 0; tries < 6; tries++) { /* LOOP OVER QUOTES UNTIL WE GET A GOOD ONE */
                                        /* stop if too many failures */
  quotno = FIRSTQUOTE+irand(LASTQUOTE-FIRSTQUOTE+1);

  /* Grab web page containing random quote */

  qfile = fopenf("/tmp/quote.%d", quotno, "r");
  if (qfile == NULL) {
    systemf(GRAB, quotno);
    qfile = fopenf("/tmp/quote.%d", quotno, "r");
  }

  /* Extract author, text, and reference from html */

  if (qfile == NULL) {
    strcpy(Quote, "Sorry, the cryptoquote service is not available today.");
    strcpy(Attribution, "The Management");
  } else {
    /* This is pretty crude code */
    for (;;) {
      s = line;
      for (;;) {
        c = fgetc(qfile);
        if (c == EOF) break;
        if (c == '\n') break;
        *s++ = c;
      }
      if (c == EOF) break;
      *s = '\0';
      if ((s = strstr(line, AUTHORTAG)) != NULL) {
        /* Identify author */
        s = s + strlen(AUTHORTAG);
        t = strstr(s, AUTHORENDTAG);
        if (t != NULL) *t = '\0';
        t = strchr(s, '(');
        if (t != NULL) *t = '\0';
        while (*s == ' ') s += 1;
        if (*s != '\0') {
          t = s + strlen(s) - 1;
          while (*t == ' ') t -= 1;
          t += 1; if (*t == ' ') *t = '\0';
	}
        while (*s == '-') s+=1;
        while (*s == ' ') s+=1;
        strcpy(Attribution, s);
        translate(Attribution);
      } else if ((s = strstr(line, QUOTETAG)) != NULL) {
        /* Extract quotation */
        s = s + strlen(QUOTETAG);
        t = strstr(s, QUOTEENDTAG);
        if (t != NULL) *t = '\0';
        if ((t = strstr(s, QUOTETAG2)) != NULL) {
          /* Trim */
          s = t + strlen(QUOTETAG2);
	}
        /* s is now the string */
        for (;;) {
          t = strstr(s, "<br>");
          if (t == NULL) break;
          *t = '\n'; t = t+1;
          strcpy(t, t+3);
	}
        /* s is now the string */
        for (;;) {
          t = strstr(s, "&nbsp;");
          if (t == NULL) break;
          *t = ' '; t = t+1;
          strcpy(t, t+5);
	}
        for (;;) {
          /* s is now the string */
          t = strstr(s, "<p>");
          if (t == NULL) break;
          *t = '\n'; t = t+1;
          strcpy(t, t+2);
	}
        /* s is now the string */
        t = s;
        for (;;) {
          t = strchr(t, '<');
          if (t == NULL) break;
          u = strchr(t, '>');
          if (u == NULL) break; /* Error? */
          memcpy(t, u+1, strlen(u+1)+1);
	}
        while (*s == '\n') s += 1;
        strcpy(Quote, s);
        translate(Quote);
      }
    }

    fclose(qfile);
    /* systemf("rm /tmp/quote.%d", quotno); */

  }

  /* DID WE GET A GOOD ONE? */

// normally we don't want to translate &nbsp; to &wsfj; etc, but in the case
// of Bartleby, all their entity references seem to be of the form &#123; so
// they translate correctly.  I had to do this because I was finding that several
// quotations in a row would fail this test, leaving us with the most-recently-tried
// one, which was often much shorter than the minimum length of 100 and _very_
// hard to decode.

  if ((strlen(Quote) > 100)
//      && (strchr(Quote, '&') == NULL)
//      && (strchr(Attribution, '&') == NULL)
     ) {
    break;
  }

  /* fprintf(stderr, "Rejecting: %s - %s\n", Quote, Attribution); */

  }

  fprintf(stdout, "Content-type: text/html\n");
  fprintf(stdout, "\n");
  fprintf(stdout, "<HTML>\n");
  fprintf(stdout, "<HEAD><TITLE>Crypto-quote of the Day</TITLE></HEAD>\n");
  fprintf(stdout, "<BODY BGCOLOR=\"#FFFFCC\">\n");

  fprintf(stdout, "<CENTER><H1>Crypto-quote of the Day<sup>1,2</sup></H1></CENTER>\n");

  fprintf(stdout, "<hr noshade>\n");
  fprintf(stdout, "<blockquote>\n");
  fprintf(stdout, "<center>\n");
  fprintf(stdout, "This is a resource of the\n");
  fprintf(stdout, "<A HREF=\"http://www.egroups.com/group/wordgame-programmers\"\n");
  fprintf(stdout, "><TT>wordgame-programmers@egroups.com</TT></A>\n");
  fprintf(stdout, "mailing list.<BR><BR>\n");
  fprintf(stdout, "<a href=\"http://www.egroups.com/subscribe/wordgame-programmers\">\n");
  fprintf(stdout, "<img src=\"http://www.egroups.com/img/ui/join.gif\" border=0><br><br>\n");
  fprintf(stdout, "Click to subscribe to wordgame-programmers</a>\n");
  fprintf(stdout, "</center>\n");
  fprintf(stdout, "</blockquote>\n");
  fprintf(stdout, "<hr noshade>\n");

  fprintf(stdout, "<BLOCKQUOTE><H2>%s</H2><BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<EM>- %s</EM></BLOCKQUOTE>", Quote, Attribution);

//   fprintf(stdout, "<CENTER><A HREF=\"http://members.singlepoint.net/sbryce/cryptograms/\">Cut &amp; paste the text above and click on this link to use an interactive assistant</A></CENTER><BR>\n", Quote);
  fprintf(stdout, "<CENTER><A HREF=\"http://www.oneacross.com/cryptograms/\">Cut &amp; paste the text above and click on this link to use an interactive assistant</A></CENTER><BR>\n", Quote);

  fprintf(stdout, "<BR><HR>");
//   fprintf(stdout, "All quotations come from The Oxford Dictionary of Quotations, © Oxford University Press 1999,\n");
//   fprintf(stdout, "courtesy of <A HREF=\"http://w2.xrefer.com/search.jsp\">XRefer.com</A>\n");
//   fprintf(stdout, "(<A HREF=\"http://w2.xrefer.com/entry.jsp?xrefid=%0d&secid=.1.-\">Click here for the solution.</A>)<BR><BR>\n", quotno);
///   fprintf(stdout, "All quotations come from famousquotes.tk.\n");
///   fprintf(stdout, " <A HREF=\"http://quotes.mist.ath.cx/specific.asp?id=%d\">Click here for the solution.</A><BR><BR>\n", quotno);
  fprintf(stdout, "All quotations come from The Columbia World of Quotations at bartleby.com.\n");
  fprintf(stdout, " <A HREF=\"http://www.bartleby.com/66/%d/%d.html\">Click here for the solution.</A><BR><BR>\n", quotno % 100, quotno);

  fprintf(stdout, "1: Although it says 'of the day' actually it changes every 15 minutes<BR>\n");
  fprintf(stdout, "2: These cryptograms obey the rule that a letter may not represent itself<BR>\n");
  fprintf(stdout, "<HR>\n");
  fprintf(stdout, "<A HREF=\"http://www.gtoal.com/wordgames/cryptograms.html\">Visit the Wordgame Programmer's archive, cryptoquote section.</A>\n");
  fprintf(stdout, "<HR>\n");
  fprintf(stdout, "</BODY>\n");
  fprintf(stdout, "</HTML>\n");

  /* Create random encryption table */

  /* Generate HTML output and CGI header */

  exit(0);
}