Crossfire Server, Trunk
requestinfo.cpp
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 #include "AssetsManager.h"
54 
55 /* Note that following protocol commands (was corresponding function)
56  * are in image.c and not this file, even though they are requestinfo
57  * commands:
58  * image_sums -> send_image_sums()
59  * image_info -> send_image_info()
60  *
61  * The order of the functions here is basically the order they
62  * are called in from request_info_cmd() from loop.c
63  */
64 
72  SockList sl;
73  int i;
74 
75  SockList_Init(&sl);
76  SockList_AddString(&sl, "replyinfo skill_info\n");
77  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++) {
78  size_t len;
79 
80  len = 16+strlen(skill_names[i]); /* upper bound for length */
81  if (SockList_Avail(&sl) < len) {
82  LOG(llevError, "Buffer overflow in send_skill_info, not sending all skill information\n");
83  break;
84  }
85 
86  if (params != NULL && *params == '1') {
87  if ((skill_faces[i] != NULL) && !(ns->faces_sent[skill_faces[i]->number]&NS_FACESENT_FACE))
88  esrv_send_face(ns, skill_faces[i], 0);
89  SockList_AddPrintf(&sl, "%d:%s:%d\n", i+CS_STAT_SKILLINFO, skill_names[i], skill_faces[i] ? skill_faces[i]->number : 0);
90  } else
91  SockList_AddPrintf(&sl, "%d:%s\n", i+CS_STAT_SKILLINFO, skill_names[i]);
92  }
93  Send_With_Handling(ns, &sl);
94  SockList_Term(&sl);
95 }
96 
103  SockList sl;
104  int i;
105 
106  SockList_Init(&sl);
107  SockList_AddString(&sl, "replyinfo spell_paths\n");
108  for (i = 0; i < NRSPELLPATHS; i++) {
109  size_t len;
110 
111  len = 16+strlen(spellpathnames[i]); /* upper bound for length */
112  if (SockList_Avail(&sl) < len) {
113  LOG(llevError, "Buffer overflow in send_spell_paths, not sending all spell information\n");
114  break;
115  }
116 
117  SockList_AddPrintf(&sl, "%d:%s\n", 1<<i, spellpathnames[i]);
118  }
119  Send_With_Handling(ns, &sl);
120  SockList_Term(&sl);
121 }
122 
129  SockList sl;
130  int i;
131  extern int64_t *levels;
132 
133  SockList_Init(&sl);
134  SockList_AddString(&sl, "replyinfo exp_table\n");
136  for (i = 1; i <= settings.max_level; i++) {
137  if (SockList_Avail(&sl) < 8) {
138  LOG(llevError, "Buffer overflow in send_exp_table, not sending all information\n");
139  break;
140  }
141  SockList_AddInt64(&sl, levels[i]);
142  }
143  Send_With_Handling(ns, &sl);
144  SockList_Term(&sl);
145 }
146 
147 /* This is like the AddIf... routines, but instead of
148  * checking against another value which we overwrite,
149  * we just check against 0.
150  */
151 #define AddShortAttr(New, Type) \
152  if (New) { \
153  SockList_AddChar(sl, Type); \
154  SockList_AddShort(sl, New); \
155  }
156 
168 static void send_arch_info(SockList *sl, const object *op)
169 {
170  if (op->name) {
171  SockList_AddString(sl, "name ");
172  SockList_AddLen8Data(sl, op->name, strlen(op->name));
173  }
174 
175  /* It is conceivable some may lack messages */
176  if (op->msg) {
177  SockList_AddString(sl, "msg ");
178  SockList_AddShort(sl, strlen(op->msg));
179  SockList_AddData(sl, op->msg, strlen(op->msg));
180  }
181 
182  SockList_AddString(sl, "stats ");
183  /* Only send non zero stats. More stats could be added here,
184  * but ideally, the text description (op->msg) should give information
185  * about resistances and other abilities.
186  * Send stats last - if the client gets a stat it does not understand,
187  * it stops processing this replyinfo.
188  */
189  AddShortAttr(op->stats.Str, CS_STAT_STR);
190  AddShortAttr(op->stats.Int, CS_STAT_INT);
191  AddShortAttr(op->stats.Pow, CS_STAT_POW);
192  AddShortAttr(op->stats.Wis, CS_STAT_WIS);
193  AddShortAttr(op->stats.Dex, CS_STAT_DEX);
194  AddShortAttr(op->stats.Con, CS_STAT_CON);
195  AddShortAttr(op->stats.Cha, CS_STAT_CHA);
196 
197  /* Terminator for the stats line */
198  SockList_AddChar(sl, 0);
199 
200  /* Handle any race/class_choice options -
201  * the code is exactly the same, except for
202  * name of field we are looking for.
203  */
204  if (op->type == CLASS || op->type == PLAYER) {
205  int i=1;
206  char buf[MAX_BUF];
207  const char *value, *value1;
208  char *lasts, *mychoices, *token;
209 
210  while (1) {
211  if (op->type == PLAYER) {
212  snprintf(buf, MAX_BUF, "race_choice_description_%d", i);
214  snprintf(buf, MAX_BUF, "race_choice_%d", i);
215  value1 = object_get_value(op, buf);
216  } else { /* Must be class */
217  snprintf(buf, MAX_BUF, "class_choice_description_%d", i);
219  snprintf(buf, MAX_BUF, "class_choice_%d", i);
220  value1 = object_get_value(op, buf);
221  }
222 
223  if (value && value1) {
224  SockList_AddString(sl, "choice ");
225  SockList_AddLen8Data(sl, buf, strlen(buf));
226  SockList_AddLen8Data(sl, value, strlen(value));
227  i++;
228  /* value1 now contains a list of archetypes */
229  /* Following operations modify string */
230  mychoices = strdup_local(value1);
231 
232  /* split_string() requires we have some
233  * idea on number of fields - in this case,
234  * we really have no idea - one could conceive
235  * of a choice of 50 weapons - using strtok_r
236  * is just as safe and will scale to any amount.
237  */
238  token = strtok_r(mychoices, " ", &lasts);
239  while (token) {
240  archetype *arch;
241 
243  if (arch) {
244  SockList_AddLen8Data(sl, token, strlen(token));
245  SockList_AddLen8Data(sl, arch->clone.name,
246  strlen(arch->clone.name));
247  } else {
248  LOG(llevError, "send_arch_info: Unable to find archetype %s\n", token);
249  }
250  token = strtok_r(NULL, " ", &lasts);
251  }
252  free(mychoices);
253  /* Terminator byte */
254  SockList_AddChar(sl, 0);
255  } else {
256  break;
257  }
258  }
259  }
260 
261 
262  /* Any addition to data to send should be at the end of the
263  * function - in other words, the order of data sent here should
264  * match order of addition. In that way, the newest additions are
265  * sent last, so client can process this data until it gets
266  * something it does not understand - if new data (subfields in the
267  * replyinfo) are sent first, the client basically has to stop
268  * processing once it gets something it does not understand.
269  */
270 
271 }
272 
279 static void build_race_list_reply(SockList *sl) {
280  SockList_AddString(sl, "replyinfo race_list ");
281 
282  getManager()->archetypes()->each([&sl] (const archetype *race) {
283  if (race->clone.type == PLAYER) {
284  SockList_AddPrintf(sl, "|%s", race->name);
285  }
286  });
287 }
288 
297  static SockList sl;
298  static int sl_initialized = 0;
299 
300  if (!sl_initialized) {
301  sl_initialized = 1;
302  SockList_Init(&sl);
304  }
305 
306  Send_With_Handling(ns, &sl);
307 }
308 
318  if (params == NULL) {
319  LOG(llevError, "send_race_info: IP '%s' sent bogus race_info command.\n", ns->host);
320  return;
321  }
323  SockList sl;
324 
325  SockList_Init(&sl);
326  SockList_AddPrintf(&sl, "replyinfo race_info %s\n", params);
327 
328  /* do not let the client arbitrarily request information about
329  * any archetype, so put a check in here for the right clone type.
330  */
331  if (race && race->clone.type == PLAYER) {
332  send_arch_info(&sl, &race->clone);
333  }
334 
335  Send_With_Handling(ns, &sl);
336  SockList_Term(&sl);
337 }
338 
346  SockList_Reset(sl);
347  SockList_AddString(sl, "replyinfo class_list ");
348  getManager()->archetypes()->each([&sl] (const archetype *cl) {
349  if (cl->clone.type == CLASS) {
350  SockList_AddPrintf(sl, "|%s", cl->name);
351  }
352  });
353 }
354 
363  static SockList sl;
364  static int sl_initialized = 0;
365 
366  if (!sl_initialized) {
367  sl_initialized = 1;
368  SockList_Init(&sl);
370  }
371 
372  Send_With_Handling(ns, &sl);
373 }
374 
384  if (params == NULL) {
385  LOG(llevError, "send_class_info: IP '%s' sent bogus class_info request.\n", ns->host);
386  return;
387  }
388  archetype *class_arch = try_find_archetype(params);
389  SockList sl;
390 
391  SockList_Init(&sl);
392  SockList_AddPrintf(&sl, "replyinfo class_info %s\n", params);
393 
394  /* do not let the client arbitrarily request information about
395  * any archetype, so put a check in here for the right clone type.
396  */
397  if (class_arch && class_arch->clone.type == CLASS) {
398  send_arch_info(&sl, &class_arch->clone);
399  }
400 
401  Send_With_Handling(ns, &sl);
402  SockList_Term(&sl);
403 }
404 
412  SockList sl;
413 
414  SockList_Init(&sl);
415  SockList_AddPrintf(&sl, "replyinfo startingmap\n");
416 
417  getManager()->archetypes()->each([&sl] (const archetype *m) {
418  if (m->clone.type == MAP && m->clone.subtype == MAP_TYPE_CHOICE) {
419  SockList_AddChar(&sl, INFO_MAP_ARCH_NAME);
420  SockList_AddLen16Data(&sl, m->name, strlen(m->name));
421 
422  SockList_AddChar(&sl, INFO_MAP_NAME);
423  SockList_AddLen16Data(&sl, m->clone.name, strlen(m->clone.name));
424 
425  /* In theory, this should always be set, but better not to crash
426  * if it is not.
427  */
428  if (m->clone.msg) {
429  SockList_AddChar(&sl, INFO_MAP_DESCRIPTION);
430  SockList_AddLen16Data(&sl, m->clone.msg, strlen(m->clone.msg));
431  }
432  }
433  });
434 
435  Send_With_Handling(ns, &sl);
436  SockList_Term(&sl);
437 }
438 
449 void send_file(socket_struct *ns, const char *file) {
450  char buf[MAX_BUF];
451  FILE *fp;
452  SockList sl;
453 
454  if (!strcmp(file,"motd"))
455  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
456  else if (!strcmp(file,"rules"))
457  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
458  else if (!strcmp(file,"news"))
459  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
460  else {
461  LOG(llevError,"send_file requested to send unknown file: %s\n", file);
462  return;
463  }
464  fp = fopen(buf, "r");
465  if (fp == NULL)
466  return;
467  SockList_Init(&sl);
468  SockList_AddString(&sl, "replyinfo ");
469  SockList_AddString(&sl, file);
470  SockList_AddString(&sl, "\n");
471 
472  while (fgets(buf, MAX_BUF, fp) != NULL) {
473  if (*buf == '#')
474  continue;
475  SockList_AddString(&sl, buf);
476  }
477  fclose(fp);
478  SockList_AddChar(&sl, 0); /* Null terminate it */
479  Send_With_Handling(ns, &sl);
480  SockList_Term(&sl);
481 }
482 
491  char buf[MAX_BUF];
492  int i;
493  size_t len;
494  SockList sl;
495 
496  SockList_Init(&sl);
497 
498  SockList_AddString(&sl, "replyinfo newcharinfo\n");
499  snprintf(buf, MAX_BUF, "V points %d", settings.starting_stat_points);
500  /* We add +1 to the length so that the null (terminator) byte
501  * gets included - this make processing on the client side easier.
502  */
503  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
504 
505  snprintf(buf, MAX_BUF, "V statrange %d %d",
507  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
508 
509  snprintf(buf, MAX_BUF, "V statname");
510  len = strlen(buf);
511  for (i=0; i<NUM_STATS; i++) {
512  safe_strcat(buf, " ", &len, MAX_BUF);
514  }
515 
516  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
517 
518  snprintf(buf, MAX_BUF, "R race requestinfo");
519  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
520 
521  snprintf(buf, MAX_BUF, "R class requestinfo");
522  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
523 
524  snprintf(buf, MAX_BUF, "O startingmap requestinfo");
525  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
526 
527  Send_With_Handling(ns, &sl);
528  SockList_Term(&sl);
529 }
CLASS
@ CLASS
Definition: object.h:141
PLAYER
@ PLAYER
Definition: object.h:110
global.h
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Definition: newserver.h:137
settings
struct Settings settings
Definition: init.cpp:139
MAP
@ MAP
Definition: object.h:128
Settings::max_level
int16_t max_level
Definition: global.h:302
SockList_AddInt64
void SockList_AddInt64(SockList *sl, uint64_t data)
Definition: lowlevel.cpp:137
build_race_list_reply
static void build_race_list_reply(SockList *sl)
Definition: requestinfo.cpp:279
llevError
@ llevError
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
build_class_list_reply
static void build_class_list_reply(SockList *sl)
Definition: requestinfo.cpp:345
strdup_local
#define strdup_local
Definition: compat.h:29
token
Definition: token.py:1
safe_strcat
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: porting.cpp:202
archininventory.arch
arch
DIALOGCHECK MINARGS 1 MAXARGS 1
Definition: archininventory.py:16
AssetsManager.h
spellpathnames
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.cpp:239
socket_struct
Definition: newserver.h:89
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.cpp:154
CS_STAT_WIS
#define CS_STAT_WIS
Definition: newclient.h:93
CS_STAT_INT
#define CS_STAT_INT
Definition: newclient.h:92
mad_mage_user.file
file
Definition: mad_mage_user.py:15
Settings::starting_stat_min
uint8_t starting_stat_min
Definition: global.h:320
send_new_char_info
void send_new_char_info(socket_struct *ns)
Definition: requestinfo.cpp:490
send_arch_info
static void send_arch_info(SockList *sl, const object *op)
Definition: requestinfo.cpp:168
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.cpp:71
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4339
buf
StringBuffer * buf
Definition: readable.cpp:1611
getManager
AssetsManager * getManager()
Definition: assets.cpp:309
archt
Definition: object.h:472
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.cpp:243
short_stat_name
const char *const short_stat_name[NUM_STATS]
Definition: living.cpp:194
m
static event_registration m
Definition: citylife.cpp:425
send_file
void send_file(socket_struct *ns, const char *file)
Definition: requestinfo.cpp:449
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.cpp:72
CS_STAT_CHA
#define CS_STAT_CHA
Definition: newclient.h:96
levels
int64_t * levels
Definition: exp.cpp:26
Face::number
uint16_t number
Definition: face.h:15
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.cpp:113
send_race_info
void send_race_info(socket_struct *ns, char *params)
Definition: requestinfo.cpp:317
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.cpp:103
Settings::motd
char motd[MAX_BUF]
Definition: global.h:278
socket_struct::host
char * host
Definition: newserver.h:100
Settings::rules
const char * rules
Definition: global.h:279
Settings::news
const char * news
Definition: global.h:280
skill_names
const char * skill_names[MAX_SKILLS]
Definition: skill_util.cpp:59
CS_STAT_SKILLINFO
#define CS_STAT_SKILLINFO
Definition: newclient.h:172
Settings::confdir
const char * confdir
Definition: global.h:247
sproto.h
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
AssetsCollection::each
void each(std::function< void(T *)> op)
Definition: AssetsCollection.h:158
MAP_TYPE_CHOICE
#define MAP_TYPE_CHOICE
Definition: map.h:59
send_spell_paths
void send_spell_paths(socket_struct *ns)
Definition: requestinfo.cpp:102
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.cpp:52
AssetsManager::archetypes
Archetypes * archetypes()
Definition: AssetsManager.h:44
MAX_BUF
#define MAX_BUF
Definition: define.h:35
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.cpp:62
Settings::starting_stat_points
uint8_t starting_stat_points
Definition: global.h:322
CS_STAT_STR
#define CS_STAT_STR
Definition: newclient.h:91
sounds.h
send_skill_info
void send_skill_info(socket_struct *ns, char *params)
Definition: requestinfo.cpp:71
obj::type
uint8_t type
Definition: object.h:346
SockList_AddData
void SockList_AddData(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:164
archt::clone
object clone
Definition: object.h:476
newserver.h
skill_faces
const Face * skill_faces[MAX_SKILLS]
Definition: skill_util.cpp:63
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
send_map_info
void send_map_info(socket_struct *ns)
Definition: requestinfo.cpp:411
SockList_AddLen8Data
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:176
AddShortAttr
#define AddShortAttr(New, Type)
Definition: requestinfo.cpp:151
roll-o-matic.params
params
Definition: roll-o-matic.py:193
send_class_list
void send_class_list(socket_struct *ns)
Definition: requestinfo.cpp:362
assets.h
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
send_class_info
void send_class_info(socket_struct *ns, char *params)
Definition: requestinfo.cpp:383
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:274
commands.h
CS_STAT_DEX
#define CS_STAT_DEX
Definition: newclient.h:94
send_exp_table
void send_exp_table(socket_struct *ns)
Definition: requestinfo.cpp:128
living.h
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:444
SockList
Definition: newclient.h:681
NUM_STATS
@ NUM_STATS
Definition: living.h:18
NRSPELLPATHS
#define NRSPELLPATHS
Definition: spells.h:40
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.cpp:199
Settings::starting_stat_max
uint8_t starting_stat_max
Definition: global.h:321
send_race_list
void send_race_list(socket_struct *ns)
Definition: requestinfo.cpp:296