Crossfire Server, Trunk
requestinfo.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
26 #include "global.h"
27 
28 #include <assert.h>
29 #include <fcntl.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/time.h>
33 #include <unistd.h>
34 
35 /* This block is basically taken from socket.c - I assume if it works there,
36  * it should work here.
37  */
38 #ifndef WIN32 /* ---win32 exclude unix headers */
39 #include <sys/types.h>
40 #include <sys/time.h>
41 #include <netinet/in.h>
42 #include <netinet/tcp.h>
43 #include <netdb.h>
44 #endif /* win32 */
45 
46 #include "commands.h"
47 #include "living.h"
48 #include "newserver.h"
49 #include "shared/newclient.h"
50 #include "sounds.h"
51 #include "sproto.h"
52 #include "assets.h"
53 
54 /* Note that following protocol commands (was corresponding function)
55  * are in image.c and not this file, even though they are requestinfo
56  * commands:
57  * image_sums -> send_image_sums()
58  * image_info -> send_image_info()
59  *
60  * The order of the functions here is basically the order they
61  * are called in from request_info_cmd() from loop.c
62  */
63 
71  SockList sl;
72  int i;
73 
74  SockList_Init(&sl);
75  SockList_AddString(&sl, "replyinfo skill_info\n");
76  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++) {
77  size_t len;
78 
79  len = 16+strlen(skill_names[i]); /* upper bound for length */
80  if (SockList_Avail(&sl) < len) {
81  LOG(llevError, "Buffer overflow in send_skill_info, not sending all skill information\n");
82  break;
83  }
84 
85  if (params != NULL && *params == '1') {
86  if ((skill_faces[i] != NULL) && !(ns->faces_sent[skill_faces[i]->number]&NS_FACESENT_FACE))
87  esrv_send_face(ns, skill_faces[i], 0);
88  SockList_AddPrintf(&sl, "%d:%s:%d\n", i+CS_STAT_SKILLINFO, skill_names[i], skill_faces[i] ? skill_faces[i]->number : 0);
89  } else
90  SockList_AddPrintf(&sl, "%d:%s\n", i+CS_STAT_SKILLINFO, skill_names[i]);
91  }
92  Send_With_Handling(ns, &sl);
93  SockList_Term(&sl);
94 }
95 
102  SockList sl;
103  int i;
104 
105  SockList_Init(&sl);
106  SockList_AddString(&sl, "replyinfo spell_paths\n");
107  for (i = 0; i < NRSPELLPATHS; i++) {
108  size_t len;
109 
110  len = 16+strlen(spellpathnames[i]); /* upper bound for length */
111  if (SockList_Avail(&sl) < len) {
112  LOG(llevError, "Buffer overflow in send_spell_paths, not sending all spell information\n");
113  break;
114  }
115 
116  SockList_AddPrintf(&sl, "%d:%s\n", 1<<i, spellpathnames[i]);
117  }
118  Send_With_Handling(ns, &sl);
119  SockList_Term(&sl);
120 }
121 
128  SockList sl;
129  int i;
130  extern int64_t *levels;
131 
132  SockList_Init(&sl);
133  SockList_AddString(&sl, "replyinfo exp_table\n");
135  for (i = 1; i <= settings.max_level; i++) {
136  if (SockList_Avail(&sl) < 8) {
137  LOG(llevError, "Buffer overflow in send_exp_table, not sending all information\n");
138  break;
139  }
140  SockList_AddInt64(&sl, levels[i]);
141  }
142  Send_With_Handling(ns, &sl);
143  SockList_Term(&sl);
144 }
145 
146 /* This is like the AddIf... routines, but instead of
147  * checking against another value which we overwrite,
148  * we just check against 0.
149  */
150 #define AddShortAttr(New, Type) \
151  if (New) { \
152  SockList_AddChar(sl, Type); \
153  SockList_AddShort(sl, New); \
154  }
155 
167 static void send_arch_info(SockList *sl, const object *op)
168 {
169  if (op->name) {
170  SockList_AddString(sl, "name ");
171  SockList_AddLen8Data(sl, op->name, strlen(op->name));
172  }
173 
174  /* It is conceivable some may lack messages */
175  if (op->msg) {
176  SockList_AddString(sl, "msg ");
177  SockList_AddShort(sl, strlen(op->msg));
178  SockList_AddData(sl, op->msg, strlen(op->msg));
179  }
180 
181  SockList_AddString(sl, "stats ");
182  /* Only send non zero stats. More stats could be added here,
183  * but ideally, the text description (op->msg) should give information
184  * about resistances and other abilities.
185  * Send stats last - if the client gets a stat it does not understand,
186  * it stops processing this replyinfo.
187  */
188  AddShortAttr(op->stats.Str, CS_STAT_STR);
189  AddShortAttr(op->stats.Int, CS_STAT_INT);
190  AddShortAttr(op->stats.Pow, CS_STAT_POW);
191  AddShortAttr(op->stats.Wis, CS_STAT_WIS);
192  AddShortAttr(op->stats.Dex, CS_STAT_DEX);
193  AddShortAttr(op->stats.Con, CS_STAT_CON);
194  AddShortAttr(op->stats.Cha, CS_STAT_CHA);
195 
196  /* Terminator for the stats line */
197  SockList_AddChar(sl, 0);
198 
199  /* Handle any race/class_choice options -
200  * the code is exactly the same, except for
201  * name of field we are looking for.
202  */
203  if (op->type == CLASS || op->type == PLAYER) {
204  int i=1;
205  char buf[MAX_BUF];
206  const char *value, *value1;
207  char *lasts, *mychoices, *token;
208 
209  while (1) {
210  if (op->type == PLAYER) {
211  snprintf(buf, MAX_BUF, "race_choice_description_%d", i);
213  snprintf(buf, MAX_BUF, "race_choice_%d", i);
214  value1 = object_get_value(op, buf);
215  } else { /* Must be class */
216  snprintf(buf, MAX_BUF, "class_choice_description_%d", i);
218  snprintf(buf, MAX_BUF, "class_choice_%d", i);
219  value1 = object_get_value(op, buf);
220  }
221 
222  if (value && value1) {
223  SockList_AddString(sl, "choice ");
224  SockList_AddLen8Data(sl, buf, strlen(buf));
225  SockList_AddLen8Data(sl, value, strlen(value));
226  i++;
227  /* value1 now contains a list of archetypes */
228  /* Following operations modify string */
229  mychoices = strdup_local(value1);
230 
231  /* split_string() requires we have some
232  * idea on number of fields - in this case,
233  * we really have no idea - one could conceive
234  * of a choice of 50 weapons - using strtok_r
235  * is just as safe and will scale to any amount.
236  */
237  token = strtok_r(mychoices, " ", &lasts);
238  while (token) {
239  archetype *arch;
240 
242  if (arch) {
243  SockList_AddLen8Data(sl, token, strlen(token));
244  SockList_AddLen8Data(sl, arch->clone.name,
245  strlen(arch->clone.name));
246  } else {
247  LOG(llevError, "send_arch_info: Unable to find archetype %s\n", token);
248  }
249  token = strtok_r(NULL, " ", &lasts);
250  }
251  free(mychoices);
252  /* Terminator byte */
253  SockList_AddChar(sl, 0);
254  } else {
255  break;
256  }
257  }
258  }
259 
260 
261  /* Any addition to data to send should be at the end of the
262  * function - in other words, the order of data sent here should
263  * match order of addition. In that way, the newest additions are
264  * sent last, so client can process this data until it gets
265  * something it does not understand - if new data (subfields in the
266  * replyinfo) are sent first, the client basically has to stop
267  * processing once it gets something it does not understand.
268  */
269 
270 }
271 
273 static SockList *ugly;
274 
279 static void do_race_list(archetype *race) {
280  if (race->clone.type == PLAYER) {
281  SockList_AddPrintf(ugly, "|%s", race->name);
282  }
283 }
284 
291 static void build_race_list_reply(SockList *sl) {
292  SockList_AddString(sl, "replyinfo race_list ");
293 
294  ugly = sl;
296 }
297 
306  static SockList sl;
307  static int sl_initialized = 0;
308 
309  if (!sl_initialized) {
310  sl_initialized = 1;
311  SockList_Init(&sl);
313  }
314 
315  Send_With_Handling(ns, &sl);
316 }
317 
327  if (params == NULL) {
328  LOG(llevError, "send_race_info: IP '%s' sent bogus race_info command.\n", ns->host);
329  return;
330  }
332  SockList sl;
333 
334  SockList_Init(&sl);
335  SockList_AddPrintf(&sl, "replyinfo race_info %s\n", params);
336 
337  /* do not let the client arbitrarily request information about
338  * any archetype, so put a check in here for the right clone type.
339  */
340  if (race && race->clone.type == PLAYER) {
341  send_arch_info(&sl, &race->clone);
342  }
343 
344  Send_With_Handling(ns, &sl);
345  SockList_Term(&sl);
346 }
347 
348 static void do_class_list(archetype *cl) {
349  if (cl->clone.type == CLASS) {
350  SockList_AddPrintf(ugly, "|%s", cl->name);
351  }
352 }
353 
361  SockList_Reset(sl);
362  SockList_AddString(sl, "replyinfo class_list ");
363 
364  ugly = sl;
366 }
367 
376  static SockList sl;
377  static int sl_initialized = 0;
378 
379  if (!sl_initialized) {
380  sl_initialized = 1;
381  SockList_Init(&sl);
383  }
384 
385  Send_With_Handling(ns, &sl);
386 }
387 
397  if (params == NULL) {
398  LOG(llevError, "send_class_info: IP '%s' sent bogus class_info request.\n", ns->host);
399  return;
400  }
401  archetype *class = try_find_archetype(params);
402  SockList sl;
403 
404  SockList_Init(&sl);
405  SockList_AddPrintf(&sl, "replyinfo class_info %s\n", params);
406 
407  /* do not let the client arbitrarily request information about
408  * any archetype, so put a check in here for the right clone type.
409  */
410  if (class && class->clone.type == CLASS) {
411  send_arch_info(&sl, &class->clone);
412  }
413 
414  Send_With_Handling(ns, &sl);
415  SockList_Term(&sl);
416 }
417 
423 static void do_map_info(archetype *m) {
424  if (m->clone.type == MAP && m->clone.subtype == MAP_TYPE_CHOICE) {
426  SockList_AddLen16Data(ugly, m->name, strlen(m->name));
427 
429  SockList_AddLen16Data(ugly, m->clone.name, strlen(m->clone.name));
430 
431  /* In theory, this should always be set, but better not to crash
432  * if it is not.
433  */
434  if (m->clone.msg) {
436  SockList_AddLen16Data(ugly, m->clone.msg, strlen(m->clone.msg));
437  }
438  }
439 }
440 
448  SockList sl;
449 
450  SockList_Init(&sl);
451  SockList_AddPrintf(&sl, "replyinfo startingmap\n");
452 
453  ugly = &sl;
455 
456  Send_With_Handling(ns, &sl);
457  SockList_Term(&sl);
458 }
459 
470 void send_file(socket_struct *ns, const char *file) {
471  char buf[MAX_BUF];
472  FILE *fp;
473  SockList sl;
474 
475  if (!strcmp(file,"motd"))
476  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
477  else if (!strcmp(file,"rules"))
478  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
479  else if (!strcmp(file,"news"))
480  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
481  else {
482  LOG(llevError,"send_file requested to send unknown file: %s\n", file);
483  return;
484  }
485  fp = fopen(buf, "r");
486  if (fp == NULL)
487  return;
488  SockList_Init(&sl);
489  SockList_AddString(&sl, "replyinfo ");
490  SockList_AddString(&sl, file);
491  SockList_AddString(&sl, "\n");
492 
493  while (fgets(buf, MAX_BUF, fp) != NULL) {
494  if (*buf == '#')
495  continue;
496  SockList_AddString(&sl, buf);
497  }
498  fclose(fp);
499  SockList_AddChar(&sl, 0); /* Null terminate it */
500  Send_With_Handling(ns, &sl);
501  SockList_Term(&sl);
502 }
503 
512  char buf[MAX_BUF];
513  int i;
514  size_t len;
515  SockList sl;
516 
517  SockList_Init(&sl);
518 
519  SockList_AddString(&sl, "replyinfo newcharinfo\n");
520  snprintf(buf, MAX_BUF, "V points %d", settings.starting_stat_points);
521  /* We add +1 to the length so that the null (terminator) byte
522  * gets included - this make processing on the client side easier.
523  */
524  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
525 
526  snprintf(buf, MAX_BUF, "V statrange %d %d",
528  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
529 
530  snprintf(buf, MAX_BUF, "V statname");
531  len = strlen(buf);
532  for (i=0; i<NUM_STATS; i++) {
533  safe_strcat(buf, " ", &len, MAX_BUF);
535  }
536 
537  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
538 
539  snprintf(buf, MAX_BUF, "R race requestinfo");
540  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
541 
542  snprintf(buf, MAX_BUF, "R class requestinfo");
543  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
544 
545  snprintf(buf, MAX_BUF, "O startingmap requestinfo");
546  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
547 
548  Send_With_Handling(ns, &sl);
549  SockList_Term(&sl);
550 }
CLASS
@ CLASS
Definition: object.h:138
PLAYER
@ PLAYER
Definition: object.h:107
global.h
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Definition: newserver.h:137
MAP
@ MAP
Definition: object.h:125
Settings::max_level
int16_t max_level
Definition: global.h:297
SockList_AddInt64
void SockList_AddInt64(SockList *sl, uint64_t data)
Definition: lowlevel.c:137
send_race_list
void send_race_list(socket_struct *ns)
Definition: requestinfo.c:305
llevError
@ llevError
Definition: logger.h:11
strdup_local
#define strdup_local
Definition: compat.h:29
token
Definition: token.py:1
send_class_info
void send_class_info(socket_struct *ns, char *params)
Definition: requestinfo.c:396
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
archetypes_for_each
void archetypes_for_each(arch_op op)
Definition: assets.cpp:331
socket_struct
Definition: newserver.h:89
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:154
CS_STAT_WIS
#define CS_STAT_WIS
Definition: newclient.h:93
CS_STAT_INT
#define CS_STAT_INT
Definition: newclient.h:92
send_spell_paths
void send_spell_paths(socket_struct *ns)
Definition: requestinfo.c:101
mad_mage_user.file
file
Definition: mad_mage_user.py:15
Settings::starting_stat_min
uint8_t starting_stat_min
Definition: global.h:315
send_class_list
void send_class_list(socket_struct *ns)
Definition: requestinfo.c:375
levels
int64_t * levels
Definition: exp.c:26
send_file
void send_file(socket_struct *ns, const char *file)
Definition: requestinfo.c:470
SockList_AddLen16Data
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:188
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:71
archt
Definition: object.h:469
settings
struct Settings settings
Definition: init.c:39
build_class_list_reply
static void build_class_list_reply(SockList *sl)
Definition: requestinfo.c:360
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.c:243
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4317
m
static event_registration m
Definition: citylife.cpp:427
CS_STAT_CON
#define CS_STAT_CON
Definition: newclient.h:95
esrv_send_face
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Definition: image.c:71
CS_STAT_CHA
#define CS_STAT_CHA
Definition: newclient.h:96
do_class_list
static void do_class_list(archetype *cl)
Definition: requestinfo.c:348
Face::number
uint16_t number
Definition: face.h:15
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.c:113
build_race_list_reply
static void build_race_list_reply(SockList *sl)
Definition: requestinfo.c:291
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.c:103
do_map_info
static void do_map_info(archetype *m)
Definition: requestinfo.c:423
Settings::motd
char motd[MAX_BUF]
Definition: global.h:273
socket_struct::host
char * host
Definition: newserver.h:100
Settings::rules
const char * rules
Definition: global.h:274
Settings::news
const char * news
Definition: global.h:275
send_race_info
void send_race_info(socket_struct *ns, char *params)
Definition: requestinfo.c:326
skill_names
const char * skill_names[MAX_SKILLS]
Definition: skill_util.c:59
CS_STAT_SKILLINFO
#define CS_STAT_SKILLINFO
Definition: newclient.h:172
Settings::confdir
const char * confdir
Definition: global.h:242
sproto.h
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
INFO_MAP_ARCH_NAME
#define INFO_MAP_ARCH_NAME
Definition: newclient.h:674
MAP_TYPE_CHOICE
#define MAP_TYPE_CHOICE
Definition: map.h:59
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.c:52
send_arch_info
static void send_arch_info(SockList *sl, const object *op)
Definition: requestinfo.c:167
MAX_BUF
#define MAX_BUF
Definition: define.h:35
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.c:62
Settings::starting_stat_points
uint8_t starting_stat_points
Definition: global.h:317
send_map_info
void send_map_info(socket_struct *ns)
Definition: requestinfo.c:447
CS_STAT_STR
#define CS_STAT_STR
Definition: newclient.h:91
sounds.h
obj::type
uint8_t type
Definition: object.h:343
SockList_AddData
void SockList_AddData(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:164
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:107
archt::clone
object clone
Definition: object.h:473
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
AddShortAttr
#define AddShortAttr(New, Type)
Definition: requestinfo.c:150
newserver.h
skill_faces
const Face * skill_faces[MAX_SKILLS]
Definition: skill_util.c:63
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
send_new_char_info
void send_new_char_info(socket_struct *ns)
Definition: requestinfo.c:511
SockList_AddLen8Data
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:176
roll-o-matic.params
params
Definition: roll-o-matic.py:193
assets.h
buf
StringBuffer * buf
Definition: readable.c:1610
short_stat_name
const char *const short_stat_name[NUM_STATS]
Definition: living.c:195
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
do_race_list
static void do_race_list(archetype *race)
Definition: requestinfo.c:279
send_skill_info
void send_skill_info(socket_struct *ns, char *params)
Definition: requestinfo.c:70
send_exp_table
void send_exp_table(socket_struct *ns)
Definition: requestinfo.c:127
newclient.h
CS_STAT_POW
#define CS_STAT_POW
Definition: newclient.h:108
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:288
commands.h
archt::name
sstring name
Definition: object.h:470
ugly
static SockList * ugly
Definition: requestinfo.c:273
CS_STAT_DEX
#define CS_STAT_DEX
Definition: newclient.h:94
INFO_MAP_NAME
#define INFO_MAP_NAME
Definition: newclient.h:675
living.h
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:440
SockList
Definition: newclient.h:681
NUM_STATS
@ NUM_STATS
Definition: living.h:18
INFO_MAP_DESCRIPTION
#define INFO_MAP_DESCRIPTION
Definition: newclient.h:676
safe_strcat
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: porting.c:200
NRSPELLPATHS
#define NRSPELLPATHS
Definition: spells.h:40
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:199
Settings::starting_stat_max
uint8_t starting_stat_max
Definition: global.h:316