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 {
104  (void)params;
105  SockList sl;
106 
107  SockList_Init(&sl);
108  SockList_AddString(&sl, "replyinfo skill_extra\n");
109  for (uint8_t i = 0; i < MAX_SKILLS && skill_names[i]; i++) {
110  if (skill_messages[i] == NULL)
111  continue;
112 
113  size_t len = 4 + strlen(skill_messages[i]); /* upper bound for length */
114  if (SockList_Avail(&sl) < len) {
115  LOG(llevError, "Buffer overflow in send_skill_extra, not sending all skill information\n");
116  break;
117  }
118 
121  }
122  SockList_AddShort(&sl, 0);
123  Send_With_Handling(ns, &sl);
124  SockList_Term(&sl);
125 }
126 
133  SockList sl;
134  int i;
135 
136  SockList_Init(&sl);
137  SockList_AddString(&sl, "replyinfo spell_paths\n");
138  for (i = 0; i < NRSPELLPATHS; i++) {
139  size_t len;
140 
141  len = 16+strlen(spellpathnames[i]); /* upper bound for length */
142  if (SockList_Avail(&sl) < len) {
143  LOG(llevError, "Buffer overflow in send_spell_paths, not sending all spell information\n");
144  break;
145  }
146 
147  SockList_AddPrintf(&sl, "%d:%s\n", 1<<i, spellpathnames[i]);
148  }
149  Send_With_Handling(ns, &sl);
150  SockList_Term(&sl);
151 }
152 
159  SockList sl;
160  int i;
161  extern int64_t *levels;
162 
163  SockList_Init(&sl);
164  SockList_AddString(&sl, "replyinfo exp_table\n");
166  for (i = 1; i <= settings.max_level; i++) {
167  if (SockList_Avail(&sl) < 8) {
168  LOG(llevError, "Buffer overflow in send_exp_table, not sending all information\n");
169  break;
170  }
171  SockList_AddInt64(&sl, levels[i]);
172  }
173  Send_With_Handling(ns, &sl);
174  SockList_Term(&sl);
175 }
176 
177 /* This is like the AddIf... routines, but instead of
178  * checking against another value which we overwrite,
179  * we just check against 0.
180  */
181 #define AddShortAttr(New, Type) \
182  if (New) { \
183  SockList_AddChar(sl, Type); \
184  SockList_AddShort(sl, New); \
185  }
186 
198 static void send_arch_info(SockList *sl, const object *op)
199 {
200  if (op->name) {
201  SockList_AddString(sl, "name ");
202  SockList_AddLen8Data(sl, op->name, strlen(op->name));
203  }
204 
205  /* It is conceivable some may lack messages */
206  if (op->msg) {
207  SockList_AddString(sl, "msg ");
208  SockList_AddShort(sl, strlen(op->msg));
209  SockList_AddData(sl, op->msg, strlen(op->msg));
210  }
211 
212  SockList_AddString(sl, "stats ");
213  /* Only send non zero stats. More stats could be added here,
214  * but ideally, the text description (op->msg) should give information
215  * about resistances and other abilities.
216  * Send stats last - if the client gets a stat it does not understand,
217  * it stops processing this replyinfo.
218  */
219  AddShortAttr(op->stats.Str, CS_STAT_STR);
220  AddShortAttr(op->stats.Int, CS_STAT_INT);
221  AddShortAttr(op->stats.Pow, CS_STAT_POW);
222  AddShortAttr(op->stats.Wis, CS_STAT_WIS);
223  AddShortAttr(op->stats.Dex, CS_STAT_DEX);
224  AddShortAttr(op->stats.Con, CS_STAT_CON);
225  AddShortAttr(op->stats.Cha, CS_STAT_CHA);
226 
227  /* Terminator for the stats line */
228  SockList_AddChar(sl, 0);
229 
230  /* Handle any race/class_choice options -
231  * the code is exactly the same, except for
232  * name of field we are looking for.
233  */
234  if (op->type == CLASS || op->type == PLAYER) {
235  int i=1;
236  char buf[MAX_BUF];
237  const char *value, *value1;
238  char *lasts, *mychoices, *token;
239 
240  while (1) {
241  if (op->type == PLAYER) {
242  snprintf(buf, MAX_BUF, "race_choice_description_%d", i);
244  snprintf(buf, MAX_BUF, "race_choice_%d", i);
245  value1 = object_get_value(op, buf);
246  } else { /* Must be class */
247  snprintf(buf, MAX_BUF, "class_choice_description_%d", i);
249  snprintf(buf, MAX_BUF, "class_choice_%d", i);
250  value1 = object_get_value(op, buf);
251  }
252 
253  if (value && value1) {
254  SockList_AddString(sl, "choice ");
255  SockList_AddLen8Data(sl, buf, strlen(buf));
256  SockList_AddLen8Data(sl, value, strlen(value));
257  i++;
258  /* value1 now contains a list of archetypes */
259  /* Following operations modify string */
260  mychoices = strdup_local(value1);
261 
262  /* split_string() requires we have some
263  * idea on number of fields - in this case,
264  * we really have no idea - one could conceive
265  * of a choice of 50 weapons - using strtok_r
266  * is just as safe and will scale to any amount.
267  */
268  token = strtok_r(mychoices, " ", &lasts);
269  while (token) {
270  archetype *arch;
271 
273  if (arch) {
274  SockList_AddLen8Data(sl, token, strlen(token));
275  SockList_AddLen8Data(sl, arch->clone.name,
276  strlen(arch->clone.name));
277  } else {
278  LOG(llevError, "send_arch_info: Unable to find archetype %s\n", token);
279  }
280  token = strtok_r(NULL, " ", &lasts);
281  }
282  free(mychoices);
283  /* Terminator byte */
284  SockList_AddChar(sl, 0);
285  } else {
286  break;
287  }
288  }
289  }
290 
291 
292  /* Any addition to data to send should be at the end of the
293  * function - in other words, the order of data sent here should
294  * match order of addition. In that way, the newest additions are
295  * sent last, so client can process this data until it gets
296  * something it does not understand - if new data (subfields in the
297  * replyinfo) are sent first, the client basically has to stop
298  * processing once it gets something it does not understand.
299  */
300 
301 }
302 
309 static void build_race_list_reply(SockList *sl) {
310  SockList_AddString(sl, "replyinfo race_list ");
311 
312  getManager()->archetypes()->each([&sl] (const archetype *race) {
313  if (race->clone.type == PLAYER) {
314  SockList_AddPrintf(sl, "|%s", race->name);
315  }
316  });
317 }
318 
327  static SockList sl;
328  static int sl_initialized = 0;
329 
330  if (!sl_initialized) {
331  sl_initialized = 1;
332  SockList_Init(&sl);
334  }
335 
336  Send_With_Handling(ns, &sl);
337 }
338 
348  if (params == NULL) {
349  LOG(llevError, "send_race_info: IP '%s' sent bogus race_info command.\n", ns->host);
350  return;
351  }
353  SockList sl;
354 
355  SockList_Init(&sl);
356  SockList_AddPrintf(&sl, "replyinfo race_info %s\n", params);
357 
358  /* do not let the client arbitrarily request information about
359  * any archetype, so put a check in here for the right clone type.
360  */
361  if (race && race->clone.type == PLAYER) {
362  send_arch_info(&sl, &race->clone);
363  }
364 
365  Send_With_Handling(ns, &sl);
366  SockList_Term(&sl);
367 }
368 
376  SockList_Reset(sl);
377  SockList_AddString(sl, "replyinfo class_list ");
378  getManager()->archetypes()->each([&sl] (const archetype *cl) {
379  if (cl->clone.type == CLASS) {
380  SockList_AddPrintf(sl, "|%s", cl->name);
381  }
382  });
383 }
384 
393  static SockList sl;
394  static int sl_initialized = 0;
395 
396  if (!sl_initialized) {
397  sl_initialized = 1;
398  SockList_Init(&sl);
400  }
401 
402  Send_With_Handling(ns, &sl);
403 }
404 
414  if (params == NULL) {
415  LOG(llevError, "send_class_info: IP '%s' sent bogus class_info request.\n", ns->host);
416  return;
417  }
418  archetype *class_arch = try_find_archetype(params);
419  SockList sl;
420 
421  SockList_Init(&sl);
422  SockList_AddPrintf(&sl, "replyinfo class_info %s\n", params);
423 
424  /* do not let the client arbitrarily request information about
425  * any archetype, so put a check in here for the right clone type.
426  */
427  if (class_arch && class_arch->clone.type == CLASS) {
428  send_arch_info(&sl, &class_arch->clone);
429  }
430 
431  Send_With_Handling(ns, &sl);
432  SockList_Term(&sl);
433 }
434 
442  SockList sl;
443 
444  SockList_Init(&sl);
445  SockList_AddPrintf(&sl, "replyinfo startingmap\n");
446 
447  getManager()->archetypes()->each([&sl] (const archetype *m) {
448  if (m->clone.type == MAP && m->clone.subtype == MAP_TYPE_CHOICE) {
449  SockList_AddChar(&sl, INFO_MAP_ARCH_NAME);
450  SockList_AddLen16Data(&sl, m->name, strlen(m->name));
451 
452  SockList_AddChar(&sl, INFO_MAP_NAME);
453  SockList_AddLen16Data(&sl, m->clone.name, strlen(m->clone.name));
454 
455  /* In theory, this should always be set, but better not to crash
456  * if it is not.
457  */
458  if (m->clone.msg) {
459  SockList_AddChar(&sl, INFO_MAP_DESCRIPTION);
460  SockList_AddLen16Data(&sl, m->clone.msg, strlen(m->clone.msg));
461  }
462  }
463  });
464 
465  Send_With_Handling(ns, &sl);
466  SockList_Term(&sl);
467 }
468 
479 void send_file(socket_struct *ns, const char *file) {
480  char buf[MAX_BUF];
481  FILE *fp;
482  SockList sl;
483 
484  if (!strcmp(file,"motd"))
485  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
486  else if (!strcmp(file,"rules"))
487  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
488  else if (!strcmp(file,"news"))
489  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
490  else {
491  LOG(llevError,"send_file requested to send unknown file: %s\n", file);
492  return;
493  }
494  fp = fopen(buf, "r");
495  if (fp == NULL)
496  return;
497  SockList_Init(&sl);
498  SockList_AddString(&sl, "replyinfo ");
499  SockList_AddString(&sl, file);
500  SockList_AddString(&sl, "\n");
501 
502  while (fgets(buf, MAX_BUF, fp) != NULL) {
503  if (*buf == '#')
504  continue;
505  SockList_AddString(&sl, buf);
506  }
507  fclose(fp);
508  SockList_AddChar(&sl, 0); /* Null terminate it */
509  Send_With_Handling(ns, &sl);
510  SockList_Term(&sl);
511 }
512 
521  char buf[MAX_BUF];
522  int i;
523  size_t len;
524  SockList sl;
525 
526  SockList_Init(&sl);
527 
528  SockList_AddString(&sl, "replyinfo newcharinfo\n");
529  snprintf(buf, MAX_BUF, "V points %d", settings.starting_stat_points);
530  /* We add +1 to the length so that the null (terminator) byte
531  * gets included - this make processing on the client side easier.
532  */
533  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
534 
535  snprintf(buf, MAX_BUF, "V statrange %d %d",
537  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
538 
539  snprintf(buf, MAX_BUF, "V statname");
540  len = strlen(buf);
541  for (i=0; i<NUM_STATS; i++) {
542  safe_strcat(buf, " ", &len, MAX_BUF);
544  }
545 
546  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
547 
548  snprintf(buf, MAX_BUF, "R race requestinfo");
549  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
550 
551  snprintf(buf, MAX_BUF, "R class requestinfo");
552  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
553 
554  snprintf(buf, MAX_BUF, "O startingmap requestinfo");
555  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
556 
557  Send_With_Handling(ns, &sl);
558  SockList_Term(&sl);
559 }
CLASS
@ CLASS
Definition: object.h:143
PLAYER
@ PLAYER
Definition: object.h:112
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:130
Settings::max_level
int16_t max_level
Definition: global.h:302
SockList_AddInt64
void SockList_AddInt64(SockList *sl, uint64_t data)
Definition: lowlevel.cpp:140
build_race_list_reply
static void build_race_list_reply(SockList *sl)
Definition: requestinfo.cpp:309
llevError
@ llevError
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:58
send_skill_extra
void send_skill_extra(socket_struct *ns, char *params)
Definition: requestinfo.cpp:102
build_class_list_reply
static void build_class_list_reply(SockList *sl)
Definition: requestinfo.cpp:375
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:240
socket_struct
Definition: newserver.h:89
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.cpp:157
CS_STAT_WIS
#define CS_STAT_WIS
Definition: newclient.h:82
CS_STAT_INT
#define CS_STAT_INT
Definition: newclient.h:81
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:520
send_arch_info
static void send_arch_info(SockList *sl, const object *op)
Definition: requestinfo.cpp:198
SockList_AddLen16Data
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:191
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.cpp:74
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4342
buf
StringBuffer * buf
Definition: readable.cpp:1565
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.cpp:246
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:479
CS_STAT_CON
#define CS_STAT_CON
Definition: newclient.h:84
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:85
levels
int64_t * levels
Definition: exp.cpp:26
Face::number
uint16_t number
Definition: face.h:15
Settings::motd
const char * motd
Definition: global.h:278
archetype::clone
object clone
Definition: object.h:485
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.cpp:116
send_race_info
void send_race_info(socket_struct *ns, char *params)
Definition: requestinfo.cpp:347
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.cpp:106
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
object::type
uint8_t type
Definition: object.h:348
skill_names
const char * skill_names[MAX_SKILLS]
Definition: skill_util.cpp:59
CS_STAT_SKILLINFO
#define CS_STAT_SKILLINFO
Definition: newclient.h:161
archetype
Definition: object.h:481
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:132
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.cpp:55
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
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:65
Settings::starting_stat_points
uint8_t starting_stat_points
Definition: global.h:322
CS_STAT_STR
#define CS_STAT_STR
Definition: newclient.h:80
sounds.h
send_skill_info
void send_skill_info(socket_struct *ns, char *params)
Definition: requestinfo.cpp:71
SockList_AddData
void SockList_AddData(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:167
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:441
SockList_AddLen8Data
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:179
AddShortAttr
#define AddShortAttr(New, Type)
Definition: requestinfo.cpp:181
roll-o-matic.params
params
Definition: roll-o-matic.py:193
send_class_list
void send_class_list(socket_struct *ns)
Definition: requestinfo.cpp:392
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:413
newclient.h
CS_STAT_POW
#define CS_STAT_POW
Definition: newclient.h:97
skill_messages
sstring skill_messages[MAX_SKILLS]
Definition: skill_util.cpp:69
try_find_archetype
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:270
commands.h
CS_STAT_DEX
#define CS_STAT_DEX
Definition: newclient.h:83
send_exp_table
void send_exp_table(socket_struct *ns)
Definition: requestinfo.cpp:158
living.h
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:447
SockList
Definition: newclient.h:670
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:202
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:326