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
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:309
llevError
@ llevError
Definition: logger.h:11
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
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
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:82
Settings::rules
const char * rules
Definition: global.h:279
CS_STAT_INT
#define CS_STAT_INT
Definition: newclient.h:81
Settings::starting_stat_max
uint8_t starting_stat_max
Definition: global.h:321
mad_mage_user.file
file
Definition: mad_mage_user.py:15
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:188
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:4337
AssetsManager.h
buf
StringBuffer * buf
Definition: readable.cpp:1552
getManager
AssetsManager * getManager()
Definition: assets.cpp:305
SockList
Definition: newclient.h:670
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
Settings::motd
const char * motd
Definition: global.h:278
send_file
void send_file(socket_struct *ns, const char *file)
Definition: requestinfo.cpp:479
cl
Player Stats effect how well a character can survie and interact inside the crossfire world This section discusses the various what they and how they effect the player s actions Also in this section are the stat modifiers that specific classes professions bring Player and sps the current and maximum the Current and Maximum The Current Sp can go somewhat negative When Sp is negative not all spells can be and a more negative Sp makes spell casting less likey to succeed can affect Damage and how the characters as well as how often the character can attack this affects the prices when buying and selling items if this drops the player will start losing hit points cl
Definition: stats.txt:88
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
archetype::clone
object clone
Definition: object.h:478
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:347
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.cpp:103
socket_struct::host
char * host
Definition: newserver.h:100
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
AssetsManager::archetypes
Archetypes * archetypes()
Definition: AssetsManager.h:44
archetype
Definition: object.h:474
sproto.h
MAX_SKILLS
#define MAX_SKILLS
Definition: skills.h:70
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:52
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
MAX_BUF
#define MAX_BUF
Definition: define.h:35
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.cpp:62
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:164
Settings::max_level
int16_t max_level
Definition: global.h:302
AssetsCollection::each
void each(std::function< void(T *)> op)
Definition: AssetsCollection.h:158
Settings::starting_stat_min
uint8_t starting_stat_min
Definition: global.h:320
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:176
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
Face::number
uint16_t number
Definition: face.h:15
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
Settings::starting_stat_points
uint8_t starting_stat_points
Definition: global.h:322
living.h
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:444
Settings::confdir
const char * confdir
Definition: global.h:247
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
send_race_list
void send_race_list(socket_struct *ns)
Definition: requestinfo.cpp:326