218 lines
7.6 KiB
C
218 lines
7.6 KiB
C
/* Copyright 2007, 2008 Neil Edelman, distributed under the terms of the
|
|
GNU General Public License, see copying.txt */
|
|
|
|
/* this is a mess -Neil */
|
|
|
|
#include <stdlib.h> /* getenv(), atoi() */
|
|
#include <stdio.h> /* printf(), FILE, f*() */
|
|
#include <string.h> /* strstr() */
|
|
#include <time.h> /* time() */
|
|
|
|
/* constants */
|
|
static const char *programme = "badass";
|
|
static const char *year = "2007, 2008";
|
|
static const int versionMajor = 1;
|
|
static const int versionMinor = 0;
|
|
|
|
#define VOTE_FILE "badass.vote"
|
|
#define DESC_FILE "badass.desc"
|
|
#define ADDR_FILE "badass.addr"
|
|
#define HTML_FILE "badass.html"
|
|
#define VALID_REFERER "http://neil.chaosnet.org/"
|
|
#define TIME 256
|
|
|
|
static struct Vote {
|
|
unsigned int vote;
|
|
char *name;
|
|
char token;
|
|
} votes[] = {
|
|
{ 0, "astronaut", 'a' },
|
|
{ 0, "commando", 'c' },
|
|
{ 0, "hacker", 'h' },
|
|
{ 0, "ninja", 'n' },
|
|
{ 0, "pilot", 'p' },
|
|
{ 0, "pirate", 'i' },
|
|
{ 0, "robot", 'r' },
|
|
{ 0, "samurai", 'm' },
|
|
{ 0, "scientist", 's' },
|
|
{ 0, "spy", 'y' }
|
|
};
|
|
const static int votes_size = sizeof(votes) / sizeof(struct Vote);
|
|
|
|
char *extract_vote(char *vote);
|
|
char *votes_read(void);
|
|
char *votes_write(void);
|
|
char *votes_inc(char vote);
|
|
char *votes_html(void);
|
|
|
|
char *extract_vote(char *vote) {
|
|
FILE *fp;
|
|
char *env, *var;
|
|
|
|
/* at least it will zero */
|
|
*vote = 0;
|
|
/* check env vars */
|
|
if(!(env = getenv("REQUEST_METHOD")) || strcmp(env, "GET")) return "Invalid request method.";
|
|
if(!(env = getenv("HTTP_REFERER")) || strncmp(env, VALID_REFERER, strlen(VALID_REFERER))) return "Invalid referer.";
|
|
if(!(env = getenv("QUERY_STRING")) || !(var = strstr(env, "vote="))) return "Invalid query string.";
|
|
/* if the addr matches the ADDR do'n't vote */
|
|
if((fp = fopen(ADDR_FILE, "r"))) {
|
|
/* 256.256.256.256 - 18446744073709551615 */
|
|
char ip[17], tm[21], *rlf;
|
|
|
|
fgets(ip, sizeof(ip), fp);
|
|
if((rlf = strrchr(ip, '\n'))) *rlf = 0; /* delete lf at the end */
|
|
if(!(env = getenv("REMOTE_ADDR"))) return "REMOTE_ADDR not set.";
|
|
if(!strcmp(env, ip)) {
|
|
fgets(tm, sizeof(tm), fp);
|
|
if(atoi(tm) + TIME > time(0)) return "This remote address has voted recenty.";
|
|
}
|
|
fclose(fp);
|
|
}
|
|
/* make up the new addr */
|
|
if((fp = fopen(ADDR_FILE, "w"))) {
|
|
time_t t;
|
|
|
|
fprintf(fp, "%.16s\n", getenv("REMOTE_ADDR"));
|
|
/* attempt to insert the time */
|
|
t = time(0);
|
|
if(t == (time_t)-1) fprintf(fp, "%d\n", 0);
|
|
else fprintf(fp, "%d\n", (int)t);
|
|
fclose(fp);
|
|
}
|
|
/* though the gautlet */
|
|
*vote = var[strlen("vote=")];
|
|
return 0;
|
|
}
|
|
|
|
char *votes_read(void) {
|
|
struct Vote *votep;
|
|
FILE *fp;
|
|
char line[81], *ch, *val;
|
|
|
|
/* read in the votes */
|
|
if(!(fp = fopen(VOTE_FILE, "r"))) {
|
|
/* it's (probably) the first time */
|
|
if(!(fp = fopen(VOTE_FILE, "w"))) return "Secret archive is'n't opening.";
|
|
fclose(fp);
|
|
return 0;
|
|
}
|
|
while(fgets(line, sizeof(line), fp)) {
|
|
/* go to the first solid character in the line */
|
|
for(ch = line; *ch && (*ch <= ' ' || *ch > '~'); ch++);
|
|
/* search for a match within the token array */
|
|
for(votep = votes; votep < votes + votes_size; votep++) if(*ch == votep->token) break;
|
|
if( votep >= votes + votes_size) continue;
|
|
/* go to the first number in the line */
|
|
for(val = ch; *val && (*val < '0' || *val > '9'); val++);
|
|
/* convert the numerical string to a number and save it */
|
|
votep->vote = atoi(val);
|
|
}
|
|
fclose(fp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
char *votes_write(void) {
|
|
struct Vote *votep;
|
|
FILE *fp;
|
|
|
|
/* write each token and value to the vote file */
|
|
if(!(fp = fopen(VOTE_FILE, "w"))) return "Error storing your vote. Probably due to a file lock from another person voting at the same time.";
|
|
for(votep = votes; votep < votes + votes_size; votep++) {
|
|
fprintf(fp, "%c=%u\n", votep->token, votep->vote);
|
|
}
|
|
fclose(fp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
char *votes_inc(char vote) {
|
|
struct Vote *votep;
|
|
|
|
/* search for a match for the first letter of vote as a token */
|
|
for(votep = votes; votep < votes + votes_size; votep++) if(vote == votep->token) break;
|
|
if( votep >= votes + votes_size) return "WTF, invalid vote?";
|
|
if(votep->vote >= (unsigned short)(-1)) return "Couldn't cast vote due to a voting overflow.";
|
|
votep->vote++;
|
|
|
|
return 0;
|
|
}
|
|
|
|
char *votes_html(void) {
|
|
struct Vote *votep;
|
|
FILE *htf;
|
|
unsigned long max = 1;
|
|
unsigned char arg;
|
|
|
|
/* rewrite the HTML file */
|
|
if(!(htf = fopen(HTML_FILE, "w"))) return "Failed preparing the vote result page for updating.";
|
|
fprintf(htf, "<!doctype html public \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n\n");
|
|
fprintf(htf, "<html>\n\n");
|
|
fprintf(htf, "<head>\n");
|
|
fprintf(htf, "<title>Voting Results</title>\n");
|
|
fprintf(htf, "<meta name = \"Content-type\" http-equiv = \"Content-Type\" content = \"text/html; charset=us-ascii\">\n");
|
|
fprintf(htf, "<meta name = \"Generator\" content = \"/cgi-bin/badass/badass.cgi\">\n");
|
|
fprintf(htf, "<link rel = \"top\" href = \"http://neil.chaosnet.org/\">\n");
|
|
fprintf(htf, "<link rel = \"icon\" href = \"/favicon.ico\" type = \"image/x-icon\">\n");
|
|
fprintf(htf, "<link rel = \"shortcut icon\" href = \"/favicon.ico\" type = \"image/x-icon\">\n");
|
|
fprintf(htf, "<link rel = \"stylesheet\" href = \"/neil.css\">\n");
|
|
fprintf(htf, "</head>\n\n");
|
|
fprintf(htf, "<body>\n");
|
|
fprintf(htf, "<h1>Which of these professions is the most badass?</h1>");
|
|
fprintf(htf, "<p>\nCurrent results:\n</p>\n\n");
|
|
/* write out each name and vote */
|
|
for(votep = votes; votep < votes + votes_size; votep++) if(max < votep->vote) max = votep->vote;
|
|
for(votep = votes; votep < votes + votes_size; votep++) {
|
|
arg = ((float)255 * votep->vote) / max;
|
|
fprintf(htf, "<p><img src = \"../gifbar/gifbar.cgi?%u\" alt = \"%u\" width = 256 height = 8> ", arg, arg);
|
|
fprintf(htf, "<em>%s</em>: %u vote%c</p>", votep->name, votep->vote, (votep->vote == 1) ? ' ' : 's');
|
|
}
|
|
fprintf(htf, "<p>Go back to <a href = \"/\">http://neil.chaosnet.org/</a>.</p>\n");
|
|
fprintf(htf, "</body>\n\n");
|
|
fprintf(htf, "</html>\n");
|
|
fclose(htf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char **argv) {
|
|
char vote, *error = 0;
|
|
|
|
if((error = votes_read()) ||
|
|
(error = extract_vote(&vote)) ||
|
|
(error = votes_inc(vote)) ||
|
|
(error = votes_write()) ||
|
|
(error = votes_html())) {
|
|
printf("Content-Type: text/html; encoding=us-ascii\n\n");
|
|
printf("<!doctype html public \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">\n\n");
|
|
printf("<html>\n\n");
|
|
printf("<head>\n");
|
|
printf("<title>Voting Error</title>\n");
|
|
printf("<meta name = \"Content-type\" http-equiv = \"Content-Type\" content = \"text/html; charset=us-ascii\">\n");
|
|
printf("<meta name = \"Generator\" content = \"/cgi-bin/badass/badass.cgi\">\n");
|
|
printf("<link rel = \"top\" href = \"http://neil.chaosnet.org/\">\n");
|
|
printf("<link rel = \"icon\" href = \"/favicon.ico\" type = \"image/x-icon\">\n");
|
|
printf("<link rel = \"shortcut icon\" href = \"/favicon.ico\" type = \"image/x-icon\">\n");
|
|
printf("<link rel = \"stylesheet\" href = \"/neil.css\">\n");
|
|
printf("</head>\n\n");
|
|
printf("<body>\n");
|
|
printf("<p>\n%s\n</p>\n\n", error);
|
|
printf("<p>Version %d.%d.</p>\n\n", versionMajor, versionMinor);
|
|
printf("<p>%s Copyright %s Neil Edelman\n", programme, year);
|
|
printf("This program comes with ABSOLUTELY NO WARRANTY.\n");
|
|
printf("This is free software, and you are welcome to redistribute it\n");
|
|
printf("under certain conditions; see copying.txt.</p>\n\n");
|
|
printf("<p>\nGo back to <a href = \"/\">root</a>.\n</p>\n");
|
|
printf("</body>\n\n");
|
|
printf("</html>\n");
|
|
|
|
return EXIT_FAILURE;
|
|
}
|
|
/* http-header directing users */
|
|
printf("Location: %s\n\n", HTML_FILE);
|
|
printf("Go to the <a href = \"%s\">results</a>.\n\n", HTML_FILE);
|
|
|
|
return 0;
|
|
}
|