1 /*
2
3 eboard - chess client
4 http://www.bergo.eng.br/eboard
5 https://github.com/fbergo/eboard
6 Copyright (C) 2000-2016 Felipe Bergo
7 fbergo/at/gmail/dot/com
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23 */
24
25 #include <iostream>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include "eboard.h"
30 #include "protocol.h"
31 #include "position.h"
32 #include "chess.h"
33 #include "global.h"
34 #include "tstring.h"
35
P2PProtocol()36 P2PProtocol::P2PProtocol() {
37 tmpbuf = (char *) malloc(2048);
38
39 Chat.set("C-*");
40 ProtoGreet.set("P-(*)-(*)-(*)*"); /* (EBOARDP2P)-(software)-(protover) */
41 NameGreet.set("N-(*)*");
42 GameProp.set("G-(*)-(*)-(*)-(*)*"); /* amwhite / time / inc / variant */
43 Accept.set("A-G");
44 Move.set("M-(*)");
45 Outcome.set("R-(*)-(*)*");
46 DrawOffer.set("D-O");
47
48 Binder.add(&Chat, &ProtoGreet, &NameGreet,
49 &GameProp, &Accept, &Move, &Outcome,
50 &DrawOffer, NULL);
51
52 IdSent = IdReceived = false;
53
54 strcpy(RemotePlayer,"Remote");
55 strcpy(RemoteSoftware, "Software");
56 RemoteProtover = 1;
57
58 pad = 0;
59 GotProp = false;
60 GotDrawProp = SentDrawProp = false;
61 MyGame = 0;
62 }
63
~P2PProtocol()64 P2PProtocol::~P2PProtocol() {
65 if (tmpbuf)
66 free(tmpbuf);
67 tmpbuf = 0;
68 }
69
requiresLegalityChecking()70 bool P2PProtocol::requiresLegalityChecking() {
71 return true;
72 }
73
finalize()74 void P2PProtocol::finalize() {
75 if (pad) {
76 pad->release();
77 pad = 0;
78 }
79 }
80
hail()81 void P2PProtocol::hail() {
82 sendId();
83 }
84
sendId()85 void P2PProtocol::sendId() {
86 char z[128];
87 if (!IdSent)
88 if (global.network)
89 if (global.network->isConnected()) {
90 snprintf(z,128,"P-(EBOARDP2P)-(eboard %s)-(1)",global.Version);
91 global.network->writeLine(z);
92 snprintf(z,128,"N-(%s)",global.P2PName);
93 global.network->writeLine(z);
94 IdSent = true;
95 }
96 }
97
sendProposal(GameProposal & g)98 void P2PProtocol::sendProposal(GameProposal &g) {
99 char z[128];
100 if (global.network)
101 if (global.network->isConnected()) {
102 snprintf(z,128,"G-(%d)-(%d)-(%d)-(%s)",
103 g.AmWhite ? 0 : 1,
104 g.timecontrol.value[0], g.timecontrol.value[1], ChessGame::variantName(g.Variant));
105 global.network->writeLine(z);
106 MyProp = g;
107 global.status->setText(_("Game proposal sent."),10);
108 }
109 }
110
acceptProposal()111 void P2PProtocol::acceptProposal() {
112 char z[64];
113
114 if (GotDrawProp) {
115 draw();
116 return;
117 }
118
119 if (GotProp) {
120
121 if (MyGame) {
122 global.status->setText(_("Finish the current game first."),10);
123 return;
124 }
125 strcpy(z,"A-G");
126 if (global.network)
127 if (global.network->isConnected())
128 global.network->writeLine(z);
129 GotProp = false;
130 createGame(HisProp);
131 }
132 }
133
receiveString(char * netstring)134 void P2PProtocol::receiveString(char *netstring) {
135 int j;
136 char *p, z[256], y[128];
137
138 j = strlen(netstring);
139 if (j<2) return;
140 if (netstring[1] != '-') return;
141
142 Binder.prepare(netstring);
143
144 if (Chat.match()) {
145 global.output->append(Chat.getStarToken(0),
146 global.Colors.PrivateTell,
147 IM_PERSONAL);
148 return;
149 }
150
151 if (MyGame && Move.match()) {
152 Position cur;
153 int wc, bc;
154
155 cur = MyGame->getLastPosition();
156 cur.SANstring(Move.getStarToken(0), y);
157 cur.moveAnyNotation(Move.getStarToken(0),
158 Current.AmWhite ? BLACK : WHITE,
159 Current.Variant);
160 if (Current.AmWhite)
161 snprintf(z,256,"%d. ... %s",MoveNumber,y);
162 else
163 snprintf(z,256,"%d. %s",MoveNumber,y);
164
165 if (MoveNumber == 1)
166 wc = bc = 1000 * Current.timecontrol.value[0];
167 else {
168 MyGame->incrementActiveClock(Current.timecontrol.value[1]);
169 wc = bc = CLOCK_UNCHANGED;
170 }
171
172 MyGame->updatePosition2(cur, MoveNumber,
173 cur.sidehint?0:1,
174 wc, bc, z, true);
175
176 if (Current.AmWhite) ++MoveNumber;
177 global.BoardList.front()->setCanMove(true);
178 global.opponentMoved();
179
180 if (GotDrawProp) pad->resetDrawProp();
181 GotDrawProp = SentDrawProp = false;
182 return;
183 }
184
185 if (ProtoGreet.match()) {
186 p = ProtoGreet.getStarToken(0);
187 if (strcmp(p, "EBOARDP2P")!=0) {
188 global.status->setText(_("Protocol mismatch, disconnecting."),10);
189 global.network->close();
190 return;
191 }
192 p = ProtoGreet.getStarToken(1);
193 memset(RemoteSoftware,0,128);
194 g_strlcpy(RemoteSoftware,p,128);
195
196 RemoteProtover = atoi(ProtoGreet.getStarToken(2));
197 if (RemoteProtover < 1) {
198 global.status->setText(_("Protocol mismatch, disconnecting."),10);
199 global.network->close();
200 return;
201 }
202
203 snprintf(z,256,"Remote software: %s (eboard/p2p v.%d)",
204 RemoteSoftware,RemoteProtover);
205 global.output->append(z,global.Colors.TextBright,IM_NORMAL);
206 IdReceived = true;
207 sendId();
208
209 if (!pad) {
210 pad = new P2PPad(this);
211 pad->show();
212 }
213
214 return;
215 }
216
217 if (NameGreet.match()) {
218 memset(RemotePlayer,0,64);
219 g_strlcpy(RemotePlayer,NameGreet.getStarToken(0),64);
220 snprintf(z,256,"Remote player name: %s",
221 RemotePlayer);
222 global.output->append(z,global.Colors.TextBright,IM_NORMAL);
223 sendId();
224 return;
225 }
226
227 if (GameProp.match()) {
228 GameProposal g;
229 int a,b;
230
231 g.AmWhite = (atoi(GameProp.getStarToken(0)) != 0);
232 a = atoi(GameProp.getStarToken(1));
233 b = atoi(GameProp.getStarToken(2));
234 g.timecontrol.setIcs(a,b);
235 g.Variant = ChessGame::variantFromName(GameProp.getStarToken(3));
236
237 HisProp = g;
238 GotProp = true;
239 if (pad)
240 pad->setProposal(g);
241 snprintf(z,256,_("Received a game proposal from %s."),RemotePlayer);
242 global.output->append(z,global.Colors.TextBright,IM_NORMAL);
243 return;
244 }
245
246 if (Accept.match()) {
247 snprintf(z,256,_("%s accepted your game proposal."),RemotePlayer);
248 global.output->append(z,global.Colors.TextBright,IM_NORMAL);
249 createGame(MyProp);
250 return;
251 }
252
253 if (DrawOffer.match()) {
254 if (SentDrawProp) {
255 draw();
256 return;
257 } else {
258 char z[128];
259 pad->setDrawProp();
260 snprintf(z,128,_("%s offers a draw."),RemotePlayer);
261 global.output->append(z,global.Colors.TextBright,IM_PERSONAL);
262 GotDrawProp = true;
263 GotProp = false;
264 return;
265 }
266 }
267
268 if (Outcome.match()) {
269 p=Outcome.getStarToken(0);
270 y[0] = *p;
271 p=Outcome.getStarToken(1);
272 y[1] = *p;
273
274 switch(y[1]) {
275 case 'S': // stalemate
276 gameOver(DRAW, _("Stalemate"));
277 return;
278 case 'N': // no material
279 gameOver(DRAW, _("No material to mate"));
280 return;
281 case 'M': // checkmate
282 gameOver(y[0]=='W'?WHITE_WIN:BLACK_WIN,_("Checkmate"));
283 return;
284 case 'R': // resign
285 gameOver(y[0]=='W'?WHITE_WIN:BLACK_WIN,_("Player resigns"));
286 return;
287 case 'A': //abort
288 gameOver(UNDEF,_("Game Aborted"));
289 return;
290 case 'D': // draw by agreement
291 gameOver(DRAW, _("Drawn by agreement"));
292 return;
293 default:
294 gameOver(UNDEF, _("Unknown result"));
295 return;
296 }
297 }
298
299 if (strlen(netstring) < 200)
300 snprintf(z,256,"Got garbage: [%s]",netstring);
301 else
302 snprintf(z,256,"Got too much garbage.");
303 global.output->append(z,global.Colors.Engine,IM_NORMAL);
304 }
305
sendUserInput(char * line)306 void P2PProtocol::sendUserInput(char *line) {
307 int j;
308
309 memset(tmpbuf,0,2048);
310 snprintf(tmpbuf,2048,"C-%s> ",global.P2PName);
311 j = strlen(line);
312 strncat(tmpbuf, line, 1900);
313 if (global.network)
314 if (global.network->isConnected())
315 global.network->writeLine(tmpbuf);
316 }
317
createGame(GameProposal & g)318 void P2PProtocol::createGame(GameProposal &g) {
319 ChessGame *cg;
320 Position *p;
321
322 Current = g;
323
324 cg = new ChessGame();
325 cg->source = GS_Other;
326 cg->clock_regressive = 1;
327 cg->GameNumber=global.nextFreeGameId(P2P_GAME+1);
328 g_strlcpy(cg->PlayerName[g.AmWhite?0:1],global.P2PName,64);
329 g_strlcpy(cg->PlayerName[g.AmWhite?1:0],RemotePlayer,64);
330 cg->MyColor = g.AmWhite ? WHITE : BLACK;
331 cg->Rated = 0;
332 cg->Variant = g.Variant;
333 cg->timecontrol = g.timecontrol;
334 cg->AmPlaying = true;
335
336 global.prependGame(cg);
337 global.BoardList.front()->reset();
338
339 cg->setBoard(global.BoardList.front());
340 global.BoardList.front()->setGame(cg);
341 global.BoardList.front()->pop();
342 global.BoardList.front()->setCanMove(g.AmWhite);
343 global.BoardList.front()->repaint();
344 global.BoardList.front()->setFlipped(!g.AmWhite);
345
346 cg->acknowledgeInfo();
347 cg->fireWhiteClock(g.timecontrol.value[0], g.timecontrol.value[1]);
348
349 p = new Position();
350 cg->updatePosition2(*p,1,p->sidehint ? 0:1,
351 1000*g.timecontrol.value[0],
352 1000*g.timecontrol.value[0],
353 "0. startpos");
354 delete p;
355
356 global.status->setText(_("Game started!"),10);
357 global.gameStarted();
358
359 MyGame = cg;
360 MoveNumber = 1;
361 }
362
sendMove(int x1,int y1,int x2,int y2,int prom)363 void P2PProtocol::sendMove(int x1,int y1,int x2,int y2,int prom) {
364 char move[7], xm[12], san[16], xsan[20];
365 piece pp;
366 Position cur;
367 int wc,bc;
368
369 global.debug("P2PProtocol","sendMove");
370
371 if (!MyGame)
372 return;
373
374 pp = prom ? global.promotion->getPiece() : EMPTY;
375
376 cur = MyGame->getLastPosition();
377
378 if (!cur.isMoveLegalCartesian(x1,y1,x2,y2,
379 Current.AmWhite?WHITE:BLACK,
380 Current.Variant)) {
381 global.status->setText(_("Illegal move, not sent."), 10);
382 return;
383 }
384
385 cur.stdNotationForMove(x1,y1,x2,y2,pp,san,MyGame->Variant);
386 cur.moveCartesian(x1,y1,x2,y2,MyGame->Variant,true);
387
388 if (Current.AmWhite)
389 snprintf(xsan,20,"%d. %s",MoveNumber,san);
390 else
391 snprintf(xsan,20,"%d. ... %s",MoveNumber,san);
392
393 if (MoveNumber == 1)
394 wc = bc = 1000 * Current.timecontrol.value[0];
395 else {
396 wc = bc = CLOCK_UNCHANGED;
397 MyGame->incrementActiveClock(Current.timecontrol.value[1]);
398 }
399
400 if (!Current.AmWhite) ++MoveNumber;
401
402 MyGame->updatePosition2(cur,MoveNumber,
403 cur.sidehint ? 0:1, wc,bc, xsan);
404
405 /* -- */
406
407 move[4]=0;
408 move[5]=0;
409 move[6]=0;
410 move[0]='a'+x1;
411 move[1]='1'+y1;
412 move[2]='a'+x2;
413 move[3]='1'+y2;
414
415 if (prom) {
416 pp=global.promotion->getPiece();
417 move[4]='=';
418 switch(pp) {
419 case QUEEN: move[5]='Q'; break;
420 case ROOK: move[5]='R'; break;
421 case BISHOP: move[5]='B'; break;
422 case KNIGHT: move[5]='N'; break;
423 case KING: move[5]='K'; break;
424 }
425 }
426 snprintf(xm,12,"M-(%s)",move);
427 global.network->writeLine(xm);
428 global.BoardList.front()->setCanMove(false);
429
430 /* check if move ends the game */
431
432 if (cur.isStalemate(Current.AmWhite?BLACK:WHITE,Current.Variant)) {
433 snprintf(xm,12,"R-(D)-(S)");
434 global.network->writeLine(xm);
435 gameOver(DRAW, _("Stalemate"));
436 return;
437 }
438 if (cur.isNMDraw(Current.Variant)) {
439 snprintf(xm,12,"R-(D)-(N)");
440 global.network->writeLine(xm);
441 gameOver(DRAW, _("No material to mate"));
442 return;
443 }
444 if (cur.isMate(Current.AmWhite?BLACK:WHITE,Current.Variant)) {
445 snprintf(xm,12,"R-(%c)-(M)", Current.AmWhite?'W':'B');
446 global.network->writeLine(xm);
447 gameOver(Current.AmWhite?WHITE_WIN:BLACK_WIN, _("Checkmate"));
448 return;
449 }
450
451 if (GotDrawProp) pad->resetDrawProp();
452 GotDrawProp = SentDrawProp = false;
453 }
454
gameOver(GameResult gr,char * desc)455 void P2PProtocol::gameOver(GameResult gr, char *desc) {
456 char z[256];
457 if (!MyGame) return;
458 MyGame->endGame(desc, gr);
459
460 snprintf(z,256,_("Game over: %s"), desc);
461 global.output->append(z, global.Colors.TextBright,
462 IM_NORMAL);
463
464 if (global.AppendPlayed) {
465 if (MyGame->savePGN(global.AppendFile,true)) {
466 snprintf(z,256,_("Game appended to %s"),global.AppendFile);
467 global.status->setText(z,10);
468 }
469 }
470
471 if ((gr==WHITE_WIN && Current.AmWhite)||
472 (gr==BLACK_WIN && !Current.AmWhite))
473 global.gameWon();
474
475 if ((gr==WHITE_WIN && !Current.AmWhite)||
476 (gr==BLACK_WIN && Current.AmWhite))
477 global.gameLost();
478
479 MyGame = 0;
480 GotDrawProp = SentDrawProp = false;
481 }
482
resign()483 void P2PProtocol::resign() {
484 char z[64];
485 if (MyGame) {
486 snprintf(z,64,"R-(%c)-(R)",Current.AmWhite?'B':'W');
487 global.network->writeLine(z);
488 gameOver(Current.AmWhite?BLACK_WIN:WHITE_WIN,_("Player resigns"));
489 }
490 }
491
draw()492 void P2PProtocol::draw() {
493 char z[128];
494 if (GotDrawProp) {
495 gameOver(DRAW,_("Drawn by agreement"));
496 global.network->writeLine("R-(D)-(D)");
497 } else {
498 global.network->writeLine("D-O");
499 SentDrawProp = true;
500 g_strlcpy(z,_("Draw offer sent."),128);
501 global.status->setText(z,5);
502 }
503 }
504
adjourn()505 void P2PProtocol::adjourn() {
506 global.status->setText("Adjournment is not supported.",10);
507 }
508
abort()509 void P2PProtocol::abort() {
510 char z[64];
511 if (MyGame) {
512 snprintf(z,64,"R-(D)-(A)");
513 global.network->writeLine(z);
514 gameOver(UNDEF,_("Game Aborted"));
515 }
516 }
517
getRemotePlayer()518 char * P2PProtocol::getRemotePlayer() { return(RemotePlayer); }
519
520 /* =================================== */
521
P2PPad(P2PProtocol * _proto)522 P2PPad::P2PPad(P2PProtocol *_proto) : NonModalDialog("Direct Connection") {
523 GtkWidget *v, *t, *f, *h, *match, *f2, *v2, *h2;
524 int i;
525
526 proto = _proto;
527 setCloseable(false);
528 PropIsDraw = false;
529
530 v = gtk_vbox_new(FALSE, 2);
531 gtk_container_add(GTK_CONTAINER(widget), v);
532
533 t = gtk_table_new(4,4,FALSE);
534 gtk_table_set_row_spacings(GTK_TABLE(t), 4);
535 gtk_table_set_col_spacings(GTK_TABLE(t), 4);
536 gtk_container_set_border_width(GTK_CONTAINER(t), 4);
537
538 f = gtk_frame_new(_("Propose Game"));
539 gtk_frame_set_shadow_type(GTK_FRAME(f), GTK_SHADOW_ETCHED_IN);
540 gtk_container_set_border_width(GTK_CONTAINER(f), 4);
541
542 gtk_box_pack_start(GTK_BOX(v), f, TRUE, TRUE, 2);
543 gtk_container_add(GTK_CONTAINER(f), t);
544
545 bl[0] = new BoxedLabel(_("Your color:"));
546 bl[1] = new BoxedLabel(_("Initial time ([mm:]ss):"));
547 bl[2] = new BoxedLabel(_("Increment (secs):"));
548
549 color = new DropBox(_("White"),
550 _("Black"),NULL);
551
552 wtime = gtk_entry_new_with_max_length(8);
553 winc = gtk_entry_new_with_max_length(4);
554
555 gtk_entry_set_text(GTK_ENTRY(wtime),"45:00");
556 gtk_entry_set_text(GTK_ENTRY(winc),"0");
557
558 gtk_table_attach_defaults(GTK_TABLE(t), bl[0]->widget, 0,1, 0,1);
559 gtk_table_attach_defaults(GTK_TABLE(t), color->widget, 1,2, 0,1);
560 gtk_table_attach_defaults(GTK_TABLE(t), bl[1]->widget, 0,1, 1,2);
561 gtk_table_attach_defaults(GTK_TABLE(t), wtime, 1,2, 1,2);
562 gtk_table_attach_defaults(GTK_TABLE(t), bl[2]->widget, 0,1, 2,3);
563 gtk_table_attach_defaults(GTK_TABLE(t), winc, 1,2, 2,3);
564
565 h=gtk_hbutton_box_new();
566 gtk_button_box_set_layout(GTK_BUTTON_BOX(h), GTK_BUTTONBOX_END);
567 gtk_button_box_set_spacing(GTK_BUTTON_BOX(h), 5);
568
569 gtk_table_attach_defaults(GTK_TABLE(t), h, 0,2, 3,4);
570
571 match = gtk_button_new_with_label(_("Propose"));
572 gtk_box_pack_start(GTK_BOX(h), match, TRUE, TRUE, 0);
573
574 gtk_signal_connect(GTK_OBJECT(match),"clicked",
575 GTK_SIGNAL_FUNC(p2ppad_propose), (gpointer) this);
576
577 color->show();
578 for(i=0;i<3;i++) bl[i]->show();
579
580 f2 = gtk_frame_new(_("Last Proposal Received"));
581 gtk_frame_set_shadow_type(GTK_FRAME(f2), GTK_SHADOW_ETCHED_IN);
582 gtk_container_set_border_width(GTK_CONTAINER(f2), 4);
583 gtk_box_pack_start(GTK_BOX(v), f2, TRUE, TRUE, 2);
584
585 v2 = gtk_vbox_new(FALSE,4);
586 gtk_container_add(GTK_CONTAINER(f2), v2);
587
588 wprop = gtk_label_new(_("No proposals received."));
589 gtk_label_set_justify(GTK_LABEL(wprop), GTK_JUSTIFY_LEFT);
590 gtk_box_pack_start(GTK_BOX(v2), wprop, TRUE, TRUE, 2);
591
592 h2=gtk_hbutton_box_new();
593 gtk_button_box_set_layout(GTK_BUTTON_BOX(h2), GTK_BUTTONBOX_END);
594 gtk_button_box_set_spacing(GTK_BUTTON_BOX(h2), 5);
595 gtk_box_pack_start(GTK_BOX(v2), h2, FALSE, TRUE, 2);
596
597 wacc = gtk_button_new_with_label(_("Accept"));
598 gtk_box_pack_start(GTK_BOX(h2), wacc, TRUE, TRUE, 0);
599
600 gtk_widget_set_sensitive(wacc, FALSE);
601
602 gtk_signal_connect(GTK_OBJECT(wacc),"clicked",
603 GTK_SIGNAL_FUNC(p2ppad_accept), (gpointer) this);
604
605 Gtk::show(wtime,winc,f,t,h,match, wacc, h2, wprop, v2, f2, v, NULL);
606 }
607
~P2PPad()608 P2PPad::~P2PPad(){
609 int i;
610 for(i=0;i<3;i++)
611 delete(bl[i]);
612 delete color;
613 }
614
setProposal(GameProposal & g)615 void P2PPad::setProposal(GameProposal &g) {
616 char z[512];
617
618 snprintf(z,512,_("%s (white) vs. %s (black)\n%s\n%d:%.2d %d"),
619 g.AmWhite ? global.P2PName : proto->getRemotePlayer(),
620 (!g.AmWhite) ? global.P2PName : proto->getRemotePlayer(),
621 ChessGame::variantName(g.Variant),
622 g.timecontrol.value[0] / 60,
623 g.timecontrol.value[0] % 60,
624 g.timecontrol.value[1]);
625 gtk_widget_set_sensitive(wacc, TRUE);
626 gtk_label_set_text(GTK_LABEL(wprop), z);
627 gtk_widget_queue_resize(wprop);
628 gtk_widget_queue_resize(widget);
629 PropIsDraw = false;
630 }
631
setDrawProp()632 void P2PPad::setDrawProp() {
633 char z[128];
634 snprintf(z,128,_("%s offers a draw."),proto->getRemotePlayer());
635 gtk_widget_set_sensitive(wacc, TRUE);
636 gtk_label_set_text(GTK_LABEL(wprop), z);
637 gtk_widget_queue_resize(wprop);
638 gtk_widget_queue_resize(widget);
639 PropIsDraw = true;
640 global.drawOffered();
641 }
642
resetDrawProp()643 void P2PPad::resetDrawProp() {
644 clearProposal();
645 }
646
clearProposal()647 void P2PPad::clearProposal() {
648 char z[64];
649 g_strlcpy(z,_("No proposals left."),64);
650 gtk_widget_set_sensitive(wacc, FALSE);
651 gtk_label_set_text(GTK_LABEL(wprop), z);
652 gtk_widget_queue_resize(wprop);
653 gtk_widget_queue_resize(widget);
654 PropIsDraw = false;
655 }
656
p2ppad_accept(GtkWidget * w,gpointer data)657 void p2ppad_accept(GtkWidget *w, gpointer data) {
658 P2PPad *me = (P2PPad *) data;
659 if (global.protocol)
660 me->proto->acceptProposal();
661 me->clearProposal();
662 }
663
p2ppad_propose(GtkWidget * w,gpointer data)664 void p2ppad_propose(GtkWidget *w, gpointer data) {
665 P2PPad *me = (P2PPad *) data;
666 GameProposal g;
667 char z[64];
668 int T,a,b;
669 tstring t;
670 string *p;
671
672 t.set(gtk_entry_get_text(GTK_ENTRY(me->wtime)));
673 a = 0;
674 while((p=t.token(":"))!=0)
675 a = (60*a) + atoi(p->c_str());
676
677 b = atoi(gtk_entry_get_text(GTK_ENTRY(me->winc)));
678 g.timecontrol.setIcs(a,b);
679 g.Variant = REGULAR;
680 g.AmWhite = (me->color->getSelection() == 0);
681
682 if (global.protocol)
683 me->proto->sendProposal(g);
684 }
685
GameProposal()686 GameProposal::GameProposal() {
687 AmWhite = false;
688 timecontrol.mode = TC_NONE;
689 Variant = REGULAR;
690 }
691
operator =(GameProposal & g)692 GameProposal GameProposal::operator=(GameProposal &g) {
693 AmWhite = g.AmWhite;
694 timecontrol = g.timecontrol;
695 Variant = g.Variant;
696 }
697