Crossfire Server, Trunk  R22010
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 
68 void send_skill_info(socket_struct *ns, char *params) {
69  SockList sl;
70  int i;
71 
72  SockList_Init(&sl);
73  SockList_AddString(&sl, "replyinfo skill_info\n");
74  for (i = 0; i < MAX_SKILLS && skill_names[i]; i++) {
75  size_t len;
76 
77  len = 16+strlen(skill_names[i]); /* upper bound for length */
78  if (SockList_Avail(&sl) < len) {
79  LOG(llevError, "Buffer overflow in send_skill_info, not sending all skill information\n");
80  break;
81  }
82 
83  if (params != NULL && *params == '1') {
84  if ((skill_faces[i] != NULL) && !(ns->faces_sent[skill_faces[i]->number]&NS_FACESENT_FACE))
85  esrv_send_face(ns, skill_faces[i], 0);
86  SockList_AddPrintf(&sl, "%d:%s:%d\n", i+CS_STAT_SKILLINFO, skill_names[i], skill_faces[i] ? skill_faces[i]->number : 0);
87  } else
88  SockList_AddPrintf(&sl, "%d:%s\n", i+CS_STAT_SKILLINFO, skill_names[i]);
89  }
90  Send_With_Handling(ns, &sl);
91  SockList_Term(&sl);
92 }
93 
98 void send_spell_paths(socket_struct *ns, char *params) {
99  SockList sl;
100  int i;
101 
102  SockList_Init(&sl);
103  SockList_AddString(&sl, "replyinfo spell_paths\n");
104  for (i = 0; i < NRSPELLPATHS; i++) {
105  size_t len;
106 
107  len = 16+strlen(spellpathnames[i]); /* upper bound for length */
108  if (SockList_Avail(&sl) < len) {
109  LOG(llevError, "Buffer overflow in send_spell_paths, not sending all spell information\n");
110  break;
111  }
112 
113  SockList_AddPrintf(&sl, "%d:%s\n", 1<<i, spellpathnames[i]);
114  }
115  Send_With_Handling(ns, &sl);
116  SockList_Term(&sl);
117 }
118 
122 void send_exp_table(socket_struct *ns, char *params) {
123  SockList sl;
124  int i;
125  extern int64_t *levels;
126 
127  SockList_Init(&sl);
128  SockList_AddString(&sl, "replyinfo exp_table\n");
130  for (i = 1; i <= settings.max_level; i++) {
131  if (SockList_Avail(&sl) < 8) {
132  LOG(llevError, "Buffer overflow in send_exp_table, not sending all information\n");
133  break;
134  }
135  SockList_AddInt64(&sl, levels[i]);
136  }
137  Send_With_Handling(ns, &sl);
138  SockList_Term(&sl);
139 }
140 
141 /* This is like the AddIf... routines, but instead of
142  * checking against another value which we overwrite,
143  * we just check against 0.
144  */
145 #define AddShortAttr(New, Type) \
146  if (New) { \
147  SockList_AddChar(sl, Type); \
148  SockList_AddShort(sl, New); \
149  }
150 
161 static void send_arch_info(SockList *sl, const object *op)
162 {
163  if (op->name) {
164  SockList_AddString(sl, "name ");
165  SockList_AddLen8Data(sl, op->name, strlen(op->name));
166  }
167 
168  /* It is conceivable some may lack messages */
169  if (op->msg) {
170  SockList_AddString(sl, "msg ");
171  SockList_AddShort(sl, strlen(op->msg));
172  SockList_AddData(sl, op->msg, strlen(op->msg));
173  }
174 
175  SockList_AddString(sl, "stats ");
176  /* Only send non zero stats. More stats could be added here,
177  * but ideally, the text description (op->msg) should give information
178  * about resistances and other abilities.
179  * Send stats last - if the client gets a stat it does not understand,
180  * it stops processing this replyinfo.
181  */
182  AddShortAttr(op->stats.Str, CS_STAT_STR);
183  AddShortAttr(op->stats.Int, CS_STAT_INT);
184  AddShortAttr(op->stats.Pow, CS_STAT_POW);
185  AddShortAttr(op->stats.Wis, CS_STAT_WIS);
186  AddShortAttr(op->stats.Dex, CS_STAT_DEX);
187  AddShortAttr(op->stats.Con, CS_STAT_CON);
188  AddShortAttr(op->stats.Cha, CS_STAT_CHA);
189 
190  /* Terminator for the stats line */
191  SockList_AddChar(sl, 0);
192 
193  /* Handle any race/class_choice options -
194  * the code is exactly the same, except for
195  * name of field we are looking for.
196  */
197  if (op->type == CLASS || op->type == PLAYER) {
198  int i=1;
199  char buf[MAX_BUF];
200  const char *value, *value1;
201  char *lasts, *mychoices, *token;
202 
203  while (1) {
204  if (op->type == PLAYER) {
205  snprintf(buf, MAX_BUF, "race_choice_description_%d", i);
206  value = object_get_value(op, buf);
207  snprintf(buf, MAX_BUF, "race_choice_%d", i);
208  value1 = object_get_value(op, buf);
209  } else { /* Must be class */
210  snprintf(buf, MAX_BUF, "class_choice_description_%d", i);
211  value = object_get_value(op, buf);
212  snprintf(buf, MAX_BUF, "class_choice_%d", i);
213  value1 = object_get_value(op, buf);
214  }
215 
216  if (value && value1) {
217  SockList_AddString(sl, "choice ");
218  SockList_AddLen8Data(sl, buf, strlen(buf));
219  SockList_AddLen8Data(sl, value, strlen(value));
220  i++;
221  /* value1 now contains a list of archetypes */
222  /* Following operations modify string */
223  mychoices = strdup_local(value1);
224 
225  /* split_string() requires we have some
226  * idea on number of fields - in this case,
227  * we really have no idea - one could conceive
228  * of a choice of 50 weapons - using strtok_r
229  * is just as safe and will scale to any amount.
230  */
231  token = strtok_r(mychoices, " ", &lasts);
232  while (token) {
233  archetype *arch;
234 
235  arch = try_find_archetype(token);
236  if (arch) {
237  SockList_AddLen8Data(sl, token, strlen(token));
238  SockList_AddLen8Data(sl, arch->clone.name,
239  strlen(arch->clone.name));
240  } else {
241  LOG(llevError, "send_arch_info: Unable to find archetype %s\n", token);
242  }
243  token = strtok_r(NULL, " ", &lasts);
244  }
245  free(mychoices);
246  /* Terminator byte */
247  SockList_AddChar(sl, 0);
248  } else {
249  break;
250  }
251  }
252  }
253 
254 
255  /* Any addition to data to send should be at the end of the
256  * function - in other words, the order of data sent here should
257  * match order of addition. In that way, the newest additions are
258  * sent last, so client can process this data until it gets
259  * something it does not understand - if new data (subfields in the
260  * replyinfo) are sent first, the client basically has to stop
261  * processing once it gets something it does not understand.
262  */
263 
264 }
265 
267 static SockList *ugly;
268 
269 static void do_race_list(archetype *race) {
270  if (race->clone.type == PLAYER) {
271  SockList_AddPrintf(ugly, "|%s", race->name);
272  }
273 }
274 
281 static void build_race_list_reply(SockList *sl) {
282  archetype *race;
283 
284  SockList_AddString(sl, "replyinfo race_list ");
285 
286  ugly = sl;
288 }
289 
299 void send_race_list(socket_struct *ns, char *params) {
300  static SockList sl;
301  static int sl_initialized = 0;
302 
303  if (!sl_initialized) {
304  sl_initialized = 1;
305  SockList_Init(&sl);
307  }
308 
309  Send_With_Handling(ns, &sl);
310 }
311 
320 void send_race_info(socket_struct *ns, char *params) {
321  archetype *race = try_find_archetype(params);
322  SockList sl;
323 
324  SockList_Init(&sl);
325  SockList_AddPrintf(&sl, "replyinfo race_info %s\n", params);
326 
327  /* do not let the client arbitrarily request information about
328  * any archetype, so put a check in here for the right clone type.
329  */
330  if (race && race->clone.type == PLAYER) {
331  send_arch_info(&sl, &race->clone);
332  }
333 
334  Send_With_Handling(ns, &sl);
335  SockList_Term(&sl);
336 }
337 
338 static void do_class_list(archetype *cl) {
339  if (cl->clone.type == CLASS) {
340  SockList_AddPrintf(ugly, "|%s", cl->name);
341  }
342 }
343 
351  archetype *cl;
352 
353  SockList_Reset(sl);
354  SockList_AddString(sl, "replyinfo class_list ");
355 
356  ugly = sl;
358 }
359 
369 void send_class_list(socket_struct *ns, char *params) {
370  static SockList sl;
371  static int sl_initialized = 0;
372 
373  if (!sl_initialized) {
374  sl_initialized = 1;
375  SockList_Init(&sl);
377  }
378 
379  Send_With_Handling(ns, &sl);
380 }
381 
390 void send_class_info(socket_struct *ns, char *params) {
391  archetype *class = try_find_archetype(params);
392  SockList sl;
393 
394  SockList_Init(&sl);
395  SockList_AddPrintf(&sl, "replyinfo class_info %s\n", params);
396 
397  /* do not let the client arbitrarily request information about
398  * any archetype, so put a check in here for the right clone type.
399  */
400  if (class && class->clone.type == CLASS) {
401  send_arch_info(&sl, &class->clone);
402  }
403 
404  Send_With_Handling(ns, &sl);
405  SockList_Term(&sl);
406 }
407 
408 static void do_map_info(archetype *m) {
409  if (m->clone.type == MAP && m->clone.subtype == MAP_TYPE_CHOICE) {
411  SockList_AddLen16Data(ugly, m->name, strlen(m->name));
412 
414  SockList_AddLen16Data(ugly, m->clone.name, strlen(m->clone.name));
415 
416  /* In theory, this should always be set, but better not to crash
417  * if it is not.
418  */
419  if (m->clone.msg) {
421  SockList_AddLen16Data(ugly, m->clone.msg, strlen(m->clone.msg));
422  }
423  }
424 }
425 
433  archetype *m;
434  SockList sl;
435 
436  SockList_Init(&sl);
437  SockList_AddPrintf(&sl, "replyinfo startingmap\n");
438 
439  ugly = &sl;
441 
442  Send_With_Handling(ns, &sl);
443  SockList_Term(&sl);
444 }
445 
456 void send_file(socket_struct *ns, const char *file) {
457  char buf[MAX_BUF];
458  FILE *fp;
459  SockList sl;
460 
461  if (!strcmp(file,"motd"))
462  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.motd);
463  else if (!strcmp(file,"rules"))
464  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.rules);
465  else if (!strcmp(file,"news"))
466  snprintf(buf, sizeof(buf), "%s/%s", settings.confdir, settings.news);
467  else {
468  LOG(llevError,"send_file requested to send unknown file: %s\n", file);
469  return;
470  }
471  fp = fopen(buf, "r");
472  if (fp == NULL)
473  return;
474  SockList_Init(&sl);
475  SockList_AddString(&sl, "replyinfo ");
476  SockList_AddString(&sl, file);
477  SockList_AddString(&sl, "\n");
478 
479  while (fgets(buf, MAX_BUF, fp) != NULL) {
480  if (*buf == '#')
481  continue;
482  SockList_AddString(&sl, buf);
483  }
484  fclose(fp);
485  SockList_AddChar(&sl, 0); /* Null terminate it */
486  Send_With_Handling(ns, &sl);
487  SockList_Term(&sl);
488 }
489 
498  char buf[MAX_BUF];
499  int i;
500  size_t len;
501  SockList sl;
502 
503  SockList_Init(&sl);
504 
505  SockList_AddString(&sl, "replyinfo newcharinfo\n");
506  snprintf(buf, MAX_BUF, "V points %d", settings.starting_stat_points);
507  /* We add +1 to the length so that the null (terminator) byte
508  * gets included - this make processing on the client side easier.
509  */
510  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
511 
512  snprintf(buf, MAX_BUF, "V statrange %d %d",
514  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
515 
516  snprintf(buf, MAX_BUF, "V statname");
517  len = strlen(buf);
518  for (i=0; i<NUM_STATS; i++) {
519  safe_strcat(buf, " ", &len, MAX_BUF);
520  safe_strcat(buf, short_stat_name[i], &len, MAX_BUF);
521  }
522 
523  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
524 
525  snprintf(buf, MAX_BUF, "R race requestinfo");
526  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
527 
528  snprintf(buf, MAX_BUF, "R class requestinfo");
529  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
530 
531  snprintf(buf, MAX_BUF, "O startingmap requestinfo");
532  SockList_AddLen8Data(&sl, buf, strlen(buf) + 1);
533 
534  Send_With_Handling(ns, &sl);
535  SockList_Term(&sl);
536 }
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:194
const char * rules
Definition: global.h:278
static void do_map_info(archetype *m)
Definition: requestinfo.c:408
const char * skill_names[MAX_SKILLS]
Definition: skill_util.c:59
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:66
#define INFO_MAP_ARCH_NAME
Definition: newclient.h:673
#define NS_FACESENT_FACE
Definition: newserver.h:137
void SockList_Init(SockList *sl)
Definition: lowlevel.c:48
uint8_t starting_stat_min
Definition: global.h:320
#define CS_STAT_INT
Definition: newclient.h:92
StringBuffer * buf
Definition: readable.c:1591
#define strdup_local
Definition: compat.h:25
char motd[MAX_BUF]
Definition: global.h:277
void archetypes_for_each(arch_op op)
Definition: assets.cpp:302
int16_t max_level
Definition: global.h:302
const Face * skill_faces[MAX_SKILLS]
Definition: skill_util.c:63
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4136
static void send_arch_info(SockList *sl, const object *op)
Definition: requestinfo.c:161
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.c:108
static void do_race_list(archetype *race)
Definition: requestinfo.c:269
void SockList_AddLen16Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:183
void send_skill_info(socket_struct *ns, char *params)
Definition: requestinfo.c:68
#define CS_STAT_DEX
Definition: newclient.h:94
void send_spell_paths(socket_struct *ns, char *params)
Definition: requestinfo.c:98
#define INFO_MAP_NAME
Definition: newclient.h:674
void send_map_info(socket_struct *ns)
Definition: requestinfo.c:432
uint8_t starting_stat_max
Definition: global.h:321
static void do_class_list(archetype *cl)
Definition: requestinfo.c:338
void send_race_list(socket_struct *ns, char *params)
Definition: requestinfo.c:299
#define CS_STAT_WIS
Definition: newclient.h:93
#define INFO_MAP_DESCRIPTION
Definition: newclient.h:675
const char *const spellpathnames[NRSPELLPATHS]
Definition: init.c:108
archetype * try_find_archetype(const char *name)
Definition: assets.cpp:255
void send_new_char_info(socket_struct *ns)
Definition: requestinfo.c:497
const char * news
Definition: global.h:279
#define strtok_r(x, y, z)
Definition: win32.h:62
void SockList_AddData(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:159
void send_file(socket_struct *ns, const char *file)
Definition: requestinfo.c:456
void SockList_Term(SockList *sl)
Definition: lowlevel.c:58
#define snprintf
Definition: win32.h:46
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:149
#define CS_STAT_CHA
Definition: newclient.h:96
void send_class_list(socket_struct *ns, char *params)
Definition: requestinfo.c:369
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.c:238
uint16_t number
Definition: face.h:15
#define CS_STAT_STR
Definition: newclient.h:91
#define MAX_BUF
Definition: define.h:35
#define NRSPELLPATHS
Definition: spells.h:40
void send_race_info(socket_struct *ns, char *params)
Definition: requestinfo.c:320
const char * confdir
Definition: global.h:244
#define AddShortAttr(New, Type)
Definition: requestinfo.c:145
signed __int64 int64_t
Definition: win32.h:168
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.c:98
void safe_strcat(char *dest, const char *orig, size_t *curlen, size_t maxlen)
Definition: porting.c:350
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Definition: image.c:71
static SockList * ugly
Definition: requestinfo.c:267
void send_exp_table(socket_struct *ns, char *params)
Definition: requestinfo.c:122
uint8_t starting_stat_points
Definition: global.h:322
#define MAP_TYPE_CHOICE
Definition: map.h:59
struct Settings settings
Definition: init.c:39
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:171
int64_t * levels
Definition: exp.c:26
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
static void build_race_list_reply(SockList *sl)
Definition: requestinfo.c:281
#define CS_STAT_POW
Definition: newclient.h:108
#define MAX_SKILLS
Definition: skills.h:70
void SockList_AddInt64(SockList *sl, uint64_t data)
Definition: lowlevel.c:132
#define CS_STAT_CON
Definition: newclient.h:95
static void build_class_list_reply(SockList *sl)
Definition: requestinfo.c:350
const char *const short_stat_name[NUM_STATS]
Definition: living.c:195
void send_class_info(socket_struct *ns, char *params)
Definition: requestinfo.c:390
#define CS_STAT_SKILLINFO
Definition: newclient.h:168
uint8_t * faces_sent
Definition: newserver.h:96
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:435