/* * Copyright (C) 1998,1999,2000 Ross Combs (rocombs@cs.nmsu.edu) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "common/setup_before.h" #include #ifdef HAVE_STDDEF_H # include #else # ifndef NULL # define NULL ((void *)0) # endif #endif #ifdef STDC_HEADERS # include #endif #include "compat/exitstatus.h" #ifdef HAVE_STRING_H # include #else # ifdef HAVE_STRINGS_H # include # endif #endif #ifdef HAVE_MEMORY_H # include #endif #include "compat/memset.h" #include "compat/memcpy.h" #include #include #include "compat/strerror.h" #ifdef TIME_WITH_SYS_TIME # include # include #else # ifdef HAVE_SYS_TIME_H # include # else # include # endif #endif #include "compat/strftime.h" #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_TERMIOS_H # include #endif #include "compat/termios.h" #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_SOCKET_H # include #endif #include "compat/socket.h" #include "compat/recv.h" #include "compat/send.h" #ifdef HAVE_SYS_PARAM_H # include #endif #ifdef HAVE_NETINET_IN_H # include #endif #include "compat/netinet_in.h" #ifdef HAVE_ARPA_INET_H # include #endif #include "compat/inet_ntoa.h" #include "compat/psock.h" #include "common/packet.h" #include "common/init_protocol.h" #include "common/udp_protocol.h" #include "common/bnet_protocol.h" #include "common/tag.h" #include "common/bn_type.h" #include "common/field_sizes.h" #include "common/network.h" #include "common/version.h" #include "common/util.h" #ifdef CLIENTDEBUG # include "common/eventlog.h" #endif #include "common/bnettime.h" #include "client.h" #include "udptest.h" #include "client_connect.h" #include "common/setup_after.h" #ifdef CLIENTDEBUG # define dprintf printf #else # define dprintf if (0) printf #endif static char const * bnclass_get_str(unsigned int class); /* FIXME: this is also in command.c */ static void usage(char const * progname); static char const * bnclass_get_str(unsigned int class) { switch (class) { case PLAYERINFO_DRTL_CLASS_WARRIOR: return "warrior"; case PLAYERINFO_DRTL_CLASS_ROGUE: return "rogue"; case PLAYERINFO_DRTL_CLASS_SORCERER: return "sorcerer"; default: return "unknown"; } } static void usage(char const * progname) { fprintf(stderr,"usage: %s [] [ []]\n",progname); fprintf(stderr, " -b, --client=SEXP report client as Brood Wars\n" " -d, --client=DRTL report client as Diablo Retail\n" " --client=DSHR report client as Diablo Shareware\n" " -s, --client=STAR report client as Starcraft (default)\n"); fprintf(stderr, " --client=SSHR report client as Starcraft Shareware\n" " -w, --client=W2BN report client as Warcraft II BNE\n" " --client=D2DV report client as Diablo II\n" " --client=D2XP report client as Diablo II: LoD\n" " --client=WAR3 report client as Warcraft III\n"); fprintf(stderr, " -o NAME, --owner=NAME report CD owner as NAME\n" " -k KEY, --cdkey=KEY report CD key as KEY\n" " -p PLR, --player=PLR print stats for player PLR\n" " --bnetd also print BNETD-specific stats\n" " --fsgs also print FSGS-specific stats\n" " -h, --help, --usage show this information and exit\n" " -v, --version print version number and exit\n"); exit(STATUS_FAILURE); } extern int main(int argc, char * argv[]) { int a; int sd; int gotplayer=0; struct sockaddr_in saddr; t_packet * packet; t_packet * rpacket; char const * cdowner=NULL; char const * cdkey=NULL; char const * clienttag=NULL; char const * servname=NULL; unsigned short servport=0; char text[MAX_MESSAGE_LEN]=""; unsigned int commpos; struct termios in_attr_old; struct termios in_attr_new; int changed_in; unsigned int count; unsigned int sessionkey; unsigned int sessionnum; unsigned int val; int fd_stdin=0; int use_bnetd=0; int use_fsgs=0; unsigned int screen_width,screen_height; int munged=0; if (argc<1 || !argv || !argv[0]) { fprintf(stderr,"bad arguments\n"); return STATUS_FAILURE; } for (a=1; a=argc) { if (str_to_ushort(argv[a],&servport)<0) { fprintf(stderr,"%s: \"%s\" should be a positive integer\n",argv[0],argv[a]); usage(argv[0]); } } else if (!servname && argv[a][0]!='-' && a+2>=argc) servname = argv[a]; else if (strcmp(argv[a],"-b")==0 || strcmp(argv[a],"--client=SEXP")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_BROODWARS; } else if (strcmp(argv[a],"-d")==0 || strcmp(argv[a],"--client=DRTL")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLORTL; } else if (strcmp(argv[a],"--client=DSHR")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_DIABLOSHR; } else if (strcmp(argv[a],"-s")==0 || strcmp(argv[a],"--client=STAR")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_STARCRAFT; } else if (strcmp(argv[a],"--client=SSHR")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_SHAREWARE; } else if (strcmp(argv[a],"-w")==0 || strcmp(argv[a],"--client=W2BN")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag); usage(argv[0]); } clienttag = CLIENTTAG_WARCIIBNE; } else if (strcmp(argv[a],"--client=D2DV")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag ); usage(argv[0]); } clienttag = CLIENTTAG_DIABLO2DV; } else if (strcmp(argv[a],"--client=D2XP")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag ); usage(argv[0]); } clienttag = CLIENTTAG_DIABLO2XP; } else if (strcmp(argv[a],"--client=WAR3")==0) { if (clienttag) { fprintf(stderr,"%s: client type was already specified as \"%s\"\n",argv[0],clienttag ); usage(argv[0]); } clienttag = CLIENTTAG_WARCRAFT3; } else if (strncmp(argv[a],"--client=",9)==0) { fprintf(stderr,"%s: unknown client tag \"%s\"\n",argv[0],&argv[a][9]); usage(argv[0]); } else if (strcmp(argv[a],"-o")==0) { if (a+1>=argc) { fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]); usage(argv[0]); } if (cdowner) { fprintf(stderr,"%s: CD owner was already specified as \"%s\"\n",argv[0],cdowner); usage(argv[0]); } cdowner = argv[++a]; } else if (strncmp(argv[a],"--owner=",8)==0) { if (cdowner) { fprintf(stderr,"%s: CD owner was already specified as \"%s\"\n",argv[0],cdowner); usage(argv[0]); } cdowner = &argv[a][8]; } else if (strcmp(argv[a],"-k")==0) { if (a+1>=argc) { fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]); usage(argv[0]); } if (cdkey) { fprintf(stderr,"%s: CD key was already specified as \"%s\"\n",argv[0],cdkey); usage(argv[0]); } cdkey = argv[++a]; } else if (strncmp(argv[a],"--cdkey=",8)==0) { if (cdkey) { fprintf(stderr,"%s: CD key was already specified as \"%s\"\n",argv[0],cdkey); usage(argv[0]); } cdkey = &argv[a][8]; } else if (strcmp(argv[a],"-p")==0) { if (a+1>=argc) { fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]); usage(argv[0]); } if (gotplayer) { fprintf(stderr,"%s: player was already specified as \"%s\"\n",argv[0],text); usage(argv[0]); } a++; if (argv[a][0]=='\0') { fprintf(stderr,"%s: player name can not be empty\n",argv[0]); usage(argv[0]); } strncpy(text,argv[a],sizeof(text)); text[sizeof(text)-1] = '\0'; gotplayer = 1; } else if (strncmp(argv[a],"--player=",9)==0) { if (gotplayer) { fprintf(stderr,"%s: player was already specified as \"%s\"\n",argv[0],text); usage(argv[0]); } if (argv[a][9]=='\0') { fprintf(stderr,"%s: player name can not be empty\n",argv[0]); usage(argv[0]); } strncpy(text,&argv[a][9],sizeof(text)); text[sizeof(text)-1] = '\0'; gotplayer = 1; } else if (strcmp(argv[a],"--bnetd")==0) use_bnetd = 1; else if (strcmp(argv[a],"--fsgs")==0) use_fsgs = 1; else if (strcmp(argv[a],"-h")==0 || strcmp(argv[a],"--help")==0 || strcmp(argv[a],"--usage") ==0) usage(argv[0]); else if (strcmp(argv[a],"-v")==0 || strcmp(argv[a],"--version")==0) { printf("version "PVPGN_VERSION"\n"); return STATUS_SUCCESS; } else if (strcmp(argv[a],"--client")==0 || strcmp(argv[a],"--owner")==0 || strcmp(argv[a],"--cdkey")==0 || strcmp(argv[a],"--player")==0) { fprintf(stderr,"%s: option \"%s\" requires an argument\n",argv[0],argv[a]); usage(argv[0]); } else { fprintf(stderr,"%s: unknown option \"%s\"\n",argv[0],argv[a]); usage(argv[0]); } if (servport==0) servport = BNETD_SERV_PORT; if (!cdowner) cdowner = BNETD_DEFAULT_OWNER; if (!cdkey) cdkey = BNETD_DEFAULT_KEY; if (!clienttag) clienttag = CLIENTTAG_STARCRAFT; if (!servname) servname = BNETD_DEFAULT_HOST; if (gotplayer) changed_in = 0; /* no need to change terminal attributes */ else { fd_stdin = fileno(stdin); if (tcgetattr(fd_stdin,&in_attr_old)>=0) { in_attr_new = in_attr_old; in_attr_new.c_lflag &= ~(ECHO | ICANON); /* turn off ECHO and ICANON */ in_attr_new.c_cc[VMIN] = 1; /* require reads to return at least one byte */ in_attr_new.c_cc[VTIME] = 0; /* no timeout */ tcsetattr(fd_stdin,TCSANOW,&in_attr_new); changed_in = 1; } else { fprintf(stderr,"%s: could not set terminal attributes for stdin\n",argv[0]); changed_in = 0; } if (client_get_termsize(fd_stdin,&screen_width,&screen_height)<0) { fprintf(stderr,"%s: could not determine screen size, assuming 80x24\n",argv[0]); screen_width = 80; screen_height = 24; } } if ((sd = client_connect(argv[0],servname,servport,cdowner,cdkey,clienttag,&saddr,&sessionkey,&sessionnum,ARCHTAG_WINX86,CLIENT_COUNTRYINFO_109_GAMELANG))<0) { fprintf(stderr,"%s: fatal error during handshake\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } /* reuse this same packet over and over */ if (!(rpacket = packet_create(packet_class_bnet))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); psock_close(sd); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } if (!(packet = packet_create(packet_class_bnet))) { fprintf(stderr,"%s: could not create packet\n",argv[0]); psock_close(sd); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } packet_set_size(packet,sizeof(t_client_fileinforeq)); packet_set_type(packet,CLIENT_FILEINFOREQ); bn_int_set(&packet->u.client_fileinforeq.type,CLIENT_FILEINFOREQ_TYPE_TOS); bn_int_set(&packet->u.client_fileinforeq.unknown2,CLIENT_FILEINFOREQ_UNKNOWN2); packet_append_string(packet,CLIENT_FILEINFOREQ_FILE_TOSUSA); client_blocksend_packet(sd,packet); packet_del_ref(packet); do if (client_blockrecv_packet(sd,rpacket)<0) { fprintf(stderr,"%s: server closed connection\n",argv[0]); psock_close(sd); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } while (packet_get_type(rpacket)!=SERVER_FILEINFOREPLY); dprintf("Got FILEINFOREPLY\n"); if (!gotplayer) { munged = 1; commpos = 0; text[0] = '\0'; } for (;;) { unsigned int i; if (!gotplayer) { switch (client_get_comm("player: ",text,sizeof(text),&commpos,1,munged,screen_width)) { case -1: /* cancel or error */ break; case 0: /* timeout */ munged = 0; continue; case 1: munged = 0; if (text[0]=='\0') continue; } if (text[0]=='\0') break; printf("\r"); for (i=0; iu.client_statsreq.name_count,1); bn_int_set(&packet->u.client_statsreq.requestid,0); packet_append_string(packet,text); count = 0; if (use_bnetd) { packet_append_string(packet,"BNET\\acct\\username"); packet_append_string(packet,"BNET\\acct\\userid"); packet_append_string(packet,"BNET\\acct\\lastlogin_clienttag"); packet_append_string(packet,"BNET\\acct\\lastlogin_connection"); packet_append_string(packet,"BNET\\acct\\lastlogin_time"); packet_append_string(packet,"BNET\\acct\\firstlogin_clienttag"); packet_append_string(packet,"BNET\\acct\\firstlogin_connection"); packet_append_string(packet,"BNET\\acct\\firstlogin_time"); count += 8; } if (use_fsgs) { packet_append_string(packet,"FSGS\\Created"); count += 1; } packet_append_string(packet,"profile\\sex"); packet_append_string(packet,"profile\\age"); packet_append_string(packet,"profile\\location"); packet_append_string(packet,"profile\\description"); count += 4; if (strcmp(clienttag,"STAR")==0) { packet_append_string(packet,"Record\\STAR\\0\\last game"); packet_append_string(packet,"Record\\STAR\\0\\last game result"); packet_append_string(packet,"Record\\STAR\\0\\wins"); packet_append_string(packet,"Record\\STAR\\0\\losses"); packet_append_string(packet,"Record\\STAR\\0\\disconnects"); packet_append_string(packet,"Record\\STAR\\0\\draws"); count += 6; packet_append_string(packet,"Record\\STAR\\1\\last game"); packet_append_string(packet,"Record\\STAR\\1\\last game result"); packet_append_string(packet,"Record\\STAR\\1\\rating"); packet_append_string(packet,"Record\\STAR\\1\\active rating"); packet_append_string(packet,"Record\\STAR\\1\\high rating"); packet_append_string(packet,"Record\\STAR\\1\\rank"); packet_append_string(packet,"Record\\STAR\\1\\active rank"); packet_append_string(packet,"Record\\STAR\\1\\high rank"); packet_append_string(packet,"Record\\STAR\\1\\wins"); packet_append_string(packet,"Record\\STAR\\1\\losses"); packet_append_string(packet,"Record\\STAR\\1\\disconnects"); packet_append_string(packet,"Record\\STAR\\1\\draws"); count += 12; } else if (strcmp(clienttag,"SEXP")==0) { packet_append_string(packet,"Record\\SEXP\\0\\last game"); packet_append_string(packet,"Record\\SEXP\\0\\last game result"); packet_append_string(packet,"Record\\SEXP\\0\\wins"); packet_append_string(packet,"Record\\SEXP\\0\\losses"); packet_append_string(packet,"Record\\SEXP\\0\\disconnects"); packet_append_string(packet,"Record\\SEXP\\0\\draws"); count += 6; packet_append_string(packet,"Record\\SEXP\\1\\last game"); packet_append_string(packet,"Record\\SEXP\\1\\last game result"); packet_append_string(packet,"Record\\SEXP\\1\\rating"); packet_append_string(packet,"Record\\SEXP\\1\\active rating"); packet_append_string(packet,"Record\\SEXP\\1\\high rating"); packet_append_string(packet,"Record\\SEXP\\1\\rank"); packet_append_string(packet,"Record\\SEXP\\1\\active rank"); packet_append_string(packet,"Record\\SEXP\\1\\high rank"); packet_append_string(packet,"Record\\SEXP\\1\\wins"); packet_append_string(packet,"Record\\SEXP\\1\\losses"); packet_append_string(packet,"Record\\SEXP\\1\\disconnects"); packet_append_string(packet,"Record\\SEXP\\1\\draws"); count += 12; } else if (strcmp(clienttag,"SSHR")==0) { packet_append_string(packet,"Record\\SSHR\\0\\last game"); packet_append_string(packet,"Record\\SSHR\\0\\last game result"); packet_append_string(packet,"Record\\SSHR\\0\\wins"); packet_append_string(packet,"Record\\SSHR\\0\\losses"); packet_append_string(packet,"Record\\SSHR\\0\\disconnects"); packet_append_string(packet,"Record\\SSHR\\0\\draws"); count += 6; } else if (strcmp(clienttag,"DSHR")==0 || strcmp(clienttag,"DRTL")==0) { if (use_bnetd) { packet_append_string(packet,"BNET\\Record\\DRTL\\0\\level"); packet_append_string(packet,"BNET\\Record\\DRTL\\0\\class"); packet_append_string(packet,"BNET\\Record\\DRTL\\0\\strength"); packet_append_string(packet,"BNET\\Record\\DRTL\\0\\magic"); packet_append_string(packet,"BNET\\Record\\DRTL\\0\\dexterity"); packet_append_string(packet,"BNET\\Record\\DRTL\\0\\vitality"); packet_append_string(packet,"BNET\\Record\\DRTL\\0\\gold"); packet_append_string(packet,"BNET\\Record\\DRTL\\0\\diablo kills"); count += 8; } } else if (strcmp(clienttag,"W2BN")==0) { packet_append_string(packet,"Record\\W2BN\\0\\last game"); packet_append_string(packet,"Record\\W2BN\\0\\last game result"); packet_append_string(packet,"Record\\W2BN\\0\\wins"); packet_append_string(packet,"Record\\W2BN\\0\\losses"); packet_append_string(packet,"Record\\W2BN\\0\\disconnects"); packet_append_string(packet,"Record\\W2BN\\0\\draws"); count += 6; packet_append_string(packet,"Record\\W2BN\\1\\last game"); packet_append_string(packet,"Record\\W2BN\\1\\last game result"); packet_append_string(packet,"Record\\W2BN\\1\\rating"); packet_append_string(packet,"Record\\W2BN\\1\\active rating"); packet_append_string(packet,"Record\\W2BN\\1\\high rating"); packet_append_string(packet,"Record\\W2BN\\1\\rank"); packet_append_string(packet,"Record\\W2BN\\1\\active rank"); packet_append_string(packet,"Record\\W2BN\\1\\high rank"); packet_append_string(packet,"Record\\W2BN\\1\\wins"); packet_append_string(packet,"Record\\W2BN\\1\\losses"); packet_append_string(packet,"Record\\W2BN\\1\\disconnects"); packet_append_string(packet,"Record\\W2BN\\1\\draws"); count += 12; packet_append_string(packet,"Record\\W2BN\\3\\last game"); packet_append_string(packet,"Record\\W2BN\\3\\last game result"); packet_append_string(packet,"Record\\W2BN\\3\\rating"); packet_append_string(packet,"Record\\W2BN\\3\\active rating"); packet_append_string(packet,"Record\\W2BN\\3\\high rating"); packet_append_string(packet,"Record\\W2BN\\3\\rank"); packet_append_string(packet,"Record\\W2BN\\3\\active rank"); packet_append_string(packet,"Record\\W2BN\\3\\high rank"); packet_append_string(packet,"Record\\W2BN\\3\\wins"); packet_append_string(packet,"Record\\W2BN\\3\\losses"); packet_append_string(packet,"Record\\W2BN\\3\\disconnects"); packet_append_string(packet,"Record\\W2BN\\3\\draws"); count += 12; } bn_int_set(&packet->u.client_statsreq.key_count,count); client_blocksend_packet(sd,packet); packet_del_ref(packet); do if (client_blockrecv_packet(sd,rpacket)<0) { fprintf(stderr,"%s: server closed connection\n",argv[0]); if (changed_in) tcsetattr(fd_stdin,TCSAFLUSH,&in_attr_old); return STATUS_FAILURE; } while (packet_get_type(rpacket)!=SERVER_STATSREPLY); dprintf("Got STATSREPLY\n"); { unsigned int names,keys; unsigned int j; unsigned int strpos; char const * temp; unsigned int uid; struct in_addr laddr; time_t tm; char timestr[STAT_TIME_MAXLEN]; names = bn_int_get(rpacket->u.server_statsreply.name_count); keys = bn_int_get(rpacket->u.server_statsreply.key_count); printf("----\n"); strpos = sizeof(t_server_statsreply); for (i=0; i0) printf(" Level: %u\n",level); else printf(" Level: NONE\n"); if (j