Hack to bypass timeseal decoder
[capablanca.git] / lasker-2.2.3 / src / timeseal.c
1 /* 
2    Copyright 2002 Andrew Tridgell <tridge@samba.org>
3    
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8    
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13    
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.   
17  */
18
19 /*   glue code that connects the chess server to the external timeseal
20  *   decoder */
21
22 #include "includes.h"
23
24 /*
25   send a string to the decoder sub-process and return the modified (decoded) string 
26   the return value is the decoded timestamp. It will be zero if the decoder didn't
27   recognise the input as valid timeseal data
28  */
29 static unsigned decode(unsigned char *s)
30 {
31         char line[1024];
32         char *p;
33         unsigned t = 0;
34
35         snprintf(line, 1000, "%s", s); // [HGM] limit length to 1000, to prevent crashing timeseal decoder
36   
37         /* send the encoded data to the decoder process */
38         dprintf(timeseal_globals.decoder_conn, "%s\n", line);
39         
40         if (!fd_gets(line, sizeof(line), timeseal_globals.decoder_conn)) {
41                 d_printf("Bad result from timeseal decoder? (t=%u)\n", t);
42                 close(timeseal_globals.decoder_conn);
43                 timeseal_globals.decoder_conn = -1;
44                 return 0;
45         }
46         line[strlen(line)-1] = 0;
47
48         p = strchr(line, ':');
49         if (!p) {
50                 d_printf("Badly formed timeseal decoder line: [%s]\n", line);
51                 close(timeseal_globals.decoder_conn);
52                 timeseal_globals.decoder_conn = -1;
53                 return 0;
54         }
55         
56         t = atoi(line);
57         strcpy(s, p+2);
58         
59         return t;
60 }
61
62 /* 
63    initialise the timeseal decoder sub-process
64 */
65 void timeseal_init(const char *path)
66 {
67         int fd[2];
68         pid_t pid;
69         
70         /* use a socketpair to get a bi-directional pipe with large buffers */
71         if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) != 0) {
72                 d_printf("Failed to create socket pair!\n");
73                 exit(1);
74         }
75         
76         pid = fork();
77         
78         if (pid == 0) {
79                 close(fd[1]);
80                 close(0);
81                 close(1);
82                 close(2);
83                 dup2(fd[0], 0);
84                 dup2(fd[0], 1);
85                 open("/dev/null", O_WRONLY); /* stderr */
86                 execl(path, "[timeseal]", NULL);
87                 exit(1);
88         }
89         
90         timeseal_globals.decoder_conn = fd[1];
91         close(fd[0]);
92 }
93
94
95 /* 
96    parse a command line from a user on *con that may be timeseal encoded. 
97    return 1 if the command should be processed further, 0 if the command
98    should be discarded
99  */
100 int timeseal_parse(char *command, struct connection_t *con)
101 {
102         unsigned t;
103         
104         /* do we have a decoder sub-process? */
105         if (timeseal_globals.decoder_conn <= 0) return 1;
106         
107         /* are they using timeseal on this connection? */
108         if (!con->timeseal_init && !con->timeseal) return 1;
109        
110 #if 1
111        {
112        static char *key="Timestamp (FICS) v1.0 - programmed by Henrik Gram.";
113 #define SWAP(X,Y) { int h = buf[i+X]; buf[i+X] = buf[i+Y]; buf[i+Y] = h; }
114                unsigned char buf[1024]; int i, l, offs;
115                snprintf(buf, 1010, "%s\n", command);
116                offs = command[strlen(command)-1] & 0x7F;
117                l = strlen(buf);
118                for(i=0; buf[i] != '\n'; i++)
119                        buf[i] = ((buf[i] + 32) ^ key[(i+offs)%50]) & 0x7F;
120                for(i=0; i<l; i+=12) {
121                        SWAP(0,11); SWAP(4,7); SWAP(2,9);
122                }
123                t = 0;
124                for(i=0; buf[i]; i++) if(buf[i] == 0x18) {
125                        buf[i++] = 0;
126                        for(l=i; buf[l]; l++) if(buf[l] == 0x19) {
127                                buf[l] = 0; t = atoi(buf + i);
128                                break;
129                        }
130                        break;
131                }
132                if(t) strcpy(command, buf);
133        }
134 #else
135         t = decode((unsigned char *) command);
136 #endif
137         
138         if (t == 0) {
139                 /* this wasn't encoded using timeseal */
140                 d_printf("Non-timeseal data [%s]\n", command);
141                 con->timeseal_init = 0;
142                 return 1;
143         }
144         
145         if (con->timeseal_init) {
146                 con->timeseal_init = 0;
147                 con->timeseal = 1;
148                 d_printf("Connected with timeseal %s\n", command);
149                 if (strncmp(command, "TIMESTAMP|", 10) == 0) {
150                         return 0;
151                 }
152         }
153         
154         con->time = t;
155         
156         /* now check for the special move time tag */
157         if (strcmp(command, "\ 29") == 0) {
158                 int p = player_find(con->fd);
159                 struct player *pp = &player_globals.parray[p];
160                 if (p >= 0 && pp->game >= 0) {
161                         int g = pp->game;
162                         if (game_globals.garray[g].game_state.onMove != 
163                             pp->side) {
164                                 return 0;
165                         }
166                         if (pp->side == WHITE) {
167                                 if (game_globals.garray[g].wTimeWhenReceivedMove == 0) {
168                                         game_globals.garray[g].wTimeWhenReceivedMove = t;
169                                 }
170                         } else {
171                                 if (game_globals.garray[g].bTimeWhenReceivedMove == 0) {
172                                         game_globals.garray[g].bTimeWhenReceivedMove = t;
173                                 }
174                         }
175                         if (game_globals.garray[g].flag_pending != FLAG_NONE) {
176                                 ExecuteFlagCmd(p, net_globals.con[pp->socket]);
177                         }
178                 }
179                 /* we have processed this special tag - don't process it further */
180                 return 0;
181         }
182         
183         return 1;
184 }
185
186 /*
187   used to call flag on players with timeseal
188  */
189 void ExecuteFlagCmd(int p, struct connection_t *con)
190 {
191         struct player *pp = &player_globals.parray[p];
192         struct game *gg;
193
194         if (pp->game == -1) {
195                 return;
196         }
197
198         gg = &game_globals.garray[pp->game];
199
200         if (pp->side == WHITE) {
201                 gg->wRealTime -= con->time - gg->wTimeWhenReceivedMove;
202                 gg->wTimeWhenReceivedMove = con->time;
203                 if (gg->wRealTime < 0) {
204                         pcommand(pp->opponent, "flag");
205                 }
206         } else if (pp->side == BLACK) {
207                 gg->bRealTime -= con->time - gg->bTimeWhenReceivedMove;
208                 gg->bTimeWhenReceivedMove = con->time;
209                 if (gg->bRealTime < 0) {
210                         pcommand(pp->opponent, "flag");
211                 }
212         }
213
214         game_update_time(pp->game);
215         gg->flag_pending = FLAG_NONE;
216 }