source: trunk/ui_web.c @ 14

Last change on this file since 14 was 13, checked in by jtv, 14 years ago

More randomness in session ID

File size: 5.1 KB
Line 
1#include <assert.h>
2#include <ctype.h>
3#include <errno.h>
4#include <fcntl.h>
5#include <stdio.h>
6#include <stdlib.h>
7#include <string.h>
8#include <time.h>
9#include <unistd.h>
10
11#include "c_abi.h"
12
13static const char
14header[] =
15  "Content-type: text/html\n\n"
16  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
17  "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
18  "<html xml:lang=\"en\" lang=\"en\">\n"
19  "<head>"
20  "<meta http-equiv=\"Content-Type\" content=\"text/xhtml+xml; charset=utf-8\" />\n"
21  "<title>Minesweeper</title>"
22  "</head>"
23  "<body>\n",
24footer[] =
25  "</body></html>\n"
26;
27
28static const char
29  tag_cols[]="cols=",
30  tag_game[]="game=",
31  tag_intel[]="intl=",
32  tag_mines[]="mines=",
33  tag_rows[]="rows=";
34
35enum { idlen=16 };
36enum { maxsize=16384 };
37
38
39static void seed_randomizer(void)
40{
41  srand(getpid()^time(NULL)^(unsigned long)getenv("SERVER_SOFTWARE"));
42}
43
44
45static int read_id(const char input[], char buf[])
46{
47  int i;
48  strncpy(buf,input,idlen);
49  buf[idlen]='\0';
50  for (i=0; i<idlen; ++i) if (!isxdigit(buf[i])) return 0;
51  return 1;
52}
53
54
55static void set_filename(char name[], const char gameid[])
56{
57  sprintf(name, "/var/local/lib/mines/games/%s", gameid);
58}
59
60
61int main(void)
62{
63  char id[idlen*2];
64  char filename[300];
65  int rows=0, cols=0, mines=0, intelligence=mines_max_intelligence();
66  int atr=0, atc=0, coords_set=0;
67  Minefield *F = NULL;
68  const char *pos;
69
70  printf("%s", header);
71
72  id[0]='\0';
73  for (pos=getenv("QUERY_STRING"); pos; pos=strchr(pos+1,'&'))
74  {
75    if (*pos == '&') ++pos;
76    switch (*pos)
77    {
78    case 'a':
79      if (pos[1]=='t' &&
80          (pos[2]=='c' || pos[2]=='r') &&
81          pos[3]=='=')
82      {
83        coords_set = 1;
84        switch (pos[2])
85        {
86        case 'c': atc = atoi(pos+4); break;
87        case 'r': atr = atoi(pos+4); break;
88        }
89      }
90      break;
91    case 'c':
92      assert(strlen(tag_cols)==5);
93      if (strncmp(pos,tag_cols,5) == 0) cols=atoi(pos+5);
94      break;
95    case 'g':
96      assert(strlen(tag_game)==5);
97      if (strncmp(pos,tag_game,5) == 0 && !read_id(pos+5,id))
98      {
99        puts("<p><em>Invalid game identifier</em></p>");
100        puts(footer);
101        return 0;
102      }
103      break;
104    case 'i':
105      assert(strlen(tag_intel)==5);
106      if (strncmp(pos,tag_intel,5) == 0) intelligence = atoi(pos+5);
107      break;
108    case 'm':
109      assert(strlen(tag_mines)==6);
110      if (strncmp(pos,tag_mines,6) == 0) mines=atoi(pos+6);
111      break;
112    case 'r':
113      assert(strlen(tag_rows)==5);
114      if (strncmp(pos,tag_rows,5) == 0) rows=atoi(pos+5);
115      break;
116    }
117  }
118
119  if (id[0])
120  {
121    char saved[maxsize+100+1];
122    int fd = -1;
123    ssize_t bytes = 0, bytesread = 0;
124
125    set_filename(filename, id);
126    fd = open(filename, O_RDONLY);
127    if (fd == -1)
128    {
129      const int err = errno;
130      perror("Could not open game file for reading");
131      if (err == EEXIST)
132      {
133        puts("<p><em>Game not found</em></p>");
134        puts(footer);
135      }
136      exit(1);
137    }
138    do
139    {
140      bytes = read(fd, saved+bytesread, sizeof(saved)-bytesread-1);
141      if (bytes > 0) bytesread += bytes;
142    } while (bytes > 0 || (bytes == -1 && errno == EINTR));
143    if (bytes < 0)
144    {
145      perror("Error reading game");
146      exit(1);
147    }
148    close(fd);
149    F = mines_load(saved);
150    if (!F) exit(1);
151    rows = mines_rows(F);
152    cols = mines_cols(F);
153  }
154  else if (rows && cols && mines && rows*cols<=maxsize)
155  {
156    size_t idbytes = 0;
157
158    /* We have parameters.  Create new game. */
159    seed_randomizer();
160    do
161    {
162      sprintf(id+idbytes,"%*.*x",4,4,rand());
163      idbytes = strlen(id);
164    } while (idbytes < idlen);
165    id[idlen] = '\0';
166    F = mines_init(rows,cols,mines);
167    if (!F) exit(1);
168    mines_set_intelligence(F, intelligence); 
169  }
170  else
171  {
172    /* TODO: Allow visitor to start a new game! */
173  }
174
175
176  if (F)
177  {
178    int r, c;
179    int done=0;
180    const char *scriptname = getenv("SCRIPT_NAME");
181    char saved[maxsize+100+1];
182    int fd;
183    size_t bytes;
184
185    if (!mines_togo(F))
186    {
187      puts("<h1>You win.  Congratulations!</h1>");
188      done=1;
189    }
190    else if (coords_set && !mines_probe(F, atr, atc, 0))
191    {
192      puts("<h1>You lose!</h1>");
193      /* TODO: Actually stop the game here! */
194      done=1;
195    }
196
197    printf("<p>Moves: %d.  Fields to go: %d</p>\n",
198        mines_moves(F), mines_togo(F));
199    printf("<form action=\"%s\" method=\"GET\"><table>", scriptname);
200    for (r=-1; r<=rows; ++r)
201    {
202      printf("<tr>");
203      for (c=-1; c<=cols; ++c)
204      {
205        const char x = mines_at(F, r, c);
206        printf("<td>");
207        if (done || x != '^') printf("%c", x);
208        else printf("<a href=\"%s?game=%s&atr=%d&atc=%d\">=</a>",
209              scriptname,id,r,c);
210        printf("</td>");
211      }
212      puts("</tr>");
213    }
214    puts("</form></table>");
215
216    bytes = mines_save(F,saved);
217    set_filename(filename, id);
218    fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0744);
219    if (fd == -1)
220    {
221        perror("Could not open game file for writing");
222        exit(1);
223    }
224    if (write(fd, saved, bytes) < 0)
225    {
226        perror("Could not write game file");
227        unlink(filename);
228        exit(1);
229    }
230    close(fd);
231    mines_close(F);
232  }
233
234  printf("%s", footer);
235  return 0;
236}
237
Note: See TracBrowser for help on using the repository browser.