Freeciv-3.2
Loading...
Searching...
No Matches
handchat.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18#include <stdarg.h>
19#include <stdio.h>
20#include <string.h>
21
22/* utility */
23#include "fcintl.h"
24#include "log.h"
25#include "shared.h"
26#include "support.h"
27
28/* common */
29#include "chat.h"
30#include "game.h"
31#include "packets.h"
32#include "player.h"
33
34/* server */
35#include "console.h"
36#include "notify.h"
37#include "stdinhand.h"
38
39#include "handchat.h"
40
41#define MAX_LEN_CHAT_NAME (2*MAX_LEN_NAME+10) /* for form_chat_name() names */
42
43static void send_chat_msg(struct connection *pconn,
44 const struct connection *sender,
45 const struct ft_color color,
46 const char *format, ...)
48
49/**********************************************************************/
54{
55 if (NULL != sender && NULL != dest) {
56 return conn_pattern_list_match(dest->server.ignore_list, sender);
57 } else {
58 return FALSE;
59 }
60}
61
62/**********************************************************************/
67static void form_chat_name(struct connection *pconn, char *buffer, size_t len)
68{
69 struct player *pplayer = pconn->playing;
70
71 if (!pplayer
72 || pconn->observer
73 || strcmp(player_name(pplayer), ANON_PLAYER_NAME) == 0) {
74 fc_snprintf(buffer, len, "(%s)", pconn->username);
75 } else {
76 fc_snprintf(buffer, len, "%s", player_name(pplayer));
77 }
78}
79
80/**********************************************************************/
83static void send_chat_msg(struct connection *pconn,
84 const struct connection *sender,
85 const struct ft_color color,
86 const char *format, ...)
87{
88 struct packet_chat_msg packet;
89 va_list args;
90
91 va_start(args, format);
92 vpackage_chat_msg(&packet, sender, color, format, args);
93 va_end(args);
94
96}
97
98/**********************************************************************/
103static void complain_ambiguous(struct connection *pconn, const char *name,
104 int player_conn)
105{
106 switch (player_conn) {
107 case 0:
109 _("%s is an ambiguous player name-prefix."), name);
110 break;
111 case 1:
113 _("%s is an ambiguous connection name-prefix."), name);
114 break;
115 case 2:
117 _("%s is an anonymous name. Use connection name."), name);
118 break;
119 default:
120 log_error("Unknown variant in %s(): %d.", __FUNCTION__, player_conn);
121 }
122}
123
124/**********************************************************************/
128 struct connection *dest, char *msg)
129{
131
132 form_chat_name(dest, dest_name, sizeof(dest_name));
133
134 if (conn_is_ignored(sender, dest)) {
136 _("You cannot send messages to %s; you are ignored."),
137 dest_name);
138 return;
139 }
140
141 msg = skip_leading_spaces(msg);
143
145 "->*%s* %s", dest_name, msg);
146
147 if (sender != dest) {
149 "*%s* %s", sender_name, msg);
150 }
151}
152
153/**********************************************************************/
157 struct player *pdest, char *msg)
158{
159 struct packet_chat_msg packet;
161 struct connection *dest = NULL; /* The 'pdest' user. */
163
164 msg = skip_leading_spaces(msg);
166
167 /* Find the user of the player 'pdest'. */
168 conn_list_iterate(pdest->connections, pconn) {
169 if (!pconn->observer) {
170 /* Found it! */
173 _("You cannot send messages to %s; you are ignored."),
175 return; /* NB: stop here, don't send to observers. */
176 }
177 dest = pconn;
178 break;
179 }
181
182 /* Repeat the message for the sender. */
184 "->{%s} %s", player_name(pdest), msg);
185
186 /* Send the message to destination. */
187 if (NULL != dest && dest != sender) {
189 "{%s} %s", sender_name, msg);
190 }
191
192 /* Send the message to player observers. */
194 "{%s -> %s} %s", sender_name, player_name(pdest), msg);
195 conn_list_iterate(pdest->connections, pconn) {
196 if (pconn != dest
197 && pconn != sender
199 send_packet_chat_msg(pconn, &packet);
200 }
202 if (NULL != sender->playing
203 && !sender->observer
204 && sender->playing != pdest) {
205 /* The sender is another player. */
206 conn_list_iterate(sender->playing->connections, pconn) {
207 if (pconn != sender && !conn_is_ignored(sender, pconn)) {
208 send_packet_chat_msg(pconn, &packet);
209 }
211
212 /* Add player to event cache. */
213 players = event_cache_player_add(players, sender->playing);
214 }
215
216 event_cache_add_for_players(&packet, players);
217}
218
219/**********************************************************************/
222static void chat_msg_to_allies(struct connection *sender, char *msg)
223{
224 struct packet_chat_msg packet;
225 struct event_cache_players *players = NULL;
227
228 msg = skip_leading_spaces(msg);
230
232 _("%s to allies: %s"), sender_name, msg);
233
235 if (!pplayers_allied(sender->playing, aplayer)) {
236 continue;
237 }
238
239 conn_list_iterate(aplayer->connections, pconn) {
241 send_packet_chat_msg(pconn, &packet);
242 }
244 players = event_cache_player_add(players, aplayer);
246
247 /* Add to the event cache. */
248 event_cache_add_for_players(&packet, players);
249}
250
251/**********************************************************************/
255 char *msg)
256{
257 struct packet_chat_msg packet;
259
260 msg = skip_leading_spaces(msg);
262
264 _("%s to global observers: %s"), sender_name, msg);
265
270 }
272
273 /* Add to the event cache. */
275}
276
277/**********************************************************************/
280static void chat_msg_to_all(struct connection *sender, char *msg)
281{
282 struct packet_chat_msg packet;
284
285 msg = skip_leading_spaces(msg);
287
289 "<%s> %s", sender_name, msg);
290 con_write(C_COMMENT, "%s", packet.message);
292
293 /* Add to the event cache. */
295}
296
297/**********************************************************************/
320void handle_chat_msg_req(struct connection *pconn, const char *message)
321{
323 bool double_colon;
324
326
327 /* This loop to prevent players from sending multiple lines which can
328 * be abused */
329 for (cp = real_message; *cp != '\0'; cp++) {
330 if (*cp == '\n' || *cp == '\r') {
331 *cp = '\0';
332 break;
333 }
334 }
335
336 /* Server commands are prefixed with '/', which is an obvious
337 but confusing choice: even before this feature existed,
338 novice players were trying /who, /nick etc.
339 So consider this an incentive for IRC support,
340 or change it in chat.h - rp
341 */
343 /* Pass it to the command parser, which will chop the prefix off */
345
346 return;
347 }
348
349 /* Send to allies command */
351 /* this won't work if we aren't attached to a player */
352 if (NULL == pconn->playing && !pconn->observer) {
354 _("You are not attached to a player."));
355 return;
356 }
357
358 if (NULL != pconn->playing) {
360 } else {
362 }
363 return;
364 }
365
366 /* Want to allow private messages with "player_name: message",
367 (or "connection_name: message"), including unambiguously
368 abbreviated player/connection name, but also want to allow
369 sensible use of ':' within messages, and _also_ want to
370 notice intended private messages with (eg) mis-spelt name.
371
372 Approach:
373
374 If there is no ':', or ':' is first on line,
375 message is global (send to all players)
376 else if the ':' is double, try matching part before "::" against
377 connection names: for single match send to that connection,
378 for multiple matches complain, else goto heuristics below.
379 else try matching part before (single) ':' against player names:
380 for single match send to that player, for multiple matches
381 complain
382 else try matching against connection names: for single match send
383 to that connection, for multiple matches complain
384 else if some heuristics apply (a space anywhere before first ':')
385 then treat as global message,
386 else complain (might be a typo-ed intended private message)
387 */
388
390
391 if (cp && (cp != &real_message[0])) {
393 struct player *pdest = NULL;
394 struct connection *conn_dest = NULL;
395 char name[MAX_LEN_NAME];
396 char *cpblank;
397
399 cp - real_message + 1));
400
402 if (double_colon) {
406 return;
407 }
410 return;
411 }
412 } else {
413 /* single colon */
417 return;
418 }
421 return;
422 }
425 return;
426 /* else try for connection name match before complaining */
427 }
431 return;
432 }
435 return;
436 }
438 /* Would have done something above if connected */
440 _("%s is not connected."), player_name(pdest));
441 return;
442 }
443 }
444 /* Didn't match; check heuristics to see if this is likely
445 * to be a global message
446 */
448 if (!cpblank || (cp < cpblank)) {
449 if (double_colon) {
451 _("There is no connection by the name %s."), name);
452 } else {
454 _("There is no player nor connection by the name %s."),
455 name);
456 }
457 return;
458 }
459 }
460 /* global message: */
462}
#define CHAT_DIRECT_PREFIX
Definition chat.h:31
#define CHAT_ALLIES_PREFIX
Definition chat.h:30
#define SERVER_COMMAND_PREFIX
Definition chat.h:28
char * incite_cost
Definition comments.c:75
#define MAX_LEN_MSG
Definition conn_types.h:37
struct connection * conn_by_user_prefix(const char *user_name, enum m_pre_result *result)
Definition connection.c:398
bool conn_is_global_observer(const struct connection *pconn)
Definition connection.c:753
bool conn_pattern_list_match(const struct conn_pattern_list *plist, const struct connection *pconn)
Definition connection.c:850
#define conn_list_iterate(connlist, pconn)
Definition connection.h:108
#define conn_list_iterate_end
Definition connection.h:110
void con_write(enum rfc_status rfc_status, const char *message,...)
Definition console.c:203
@ C_COMMENT
Definition console.h:37
#define MAX_LEN_NAME
Definition fc_types.h:66
#define _(String)
Definition fcintl.h:67
const struct ft_color ftc_chat_private
const struct ft_color ftc_server
const struct ft_color ftc_warning
const struct ft_color ftc_chat_public
const struct ft_color ftc_chat_ally
struct civ_game game
Definition game.c:62
static void static bool conn_is_ignored(const struct connection *sender, const struct connection *dest)
Definition handchat.c:52
static void complain_ambiguous(struct connection *pconn, const char *name, int player_conn)
Definition handchat.c:103
static void chat_msg_to_player(struct connection *sender, struct player *pdest, char *msg)
Definition handchat.c:156
static void form_chat_name(struct connection *pconn, char *buffer, size_t len)
Definition handchat.c:67
#define MAX_LEN_CHAT_NAME
Definition handchat.c:41
static void send_chat_msg(struct connection *pconn, const struct connection *sender, const struct ft_color color, const char *format,...) fc__attribute((__format__(__printf__
Definition handchat.c:83
static void chat_msg_to_all(struct connection *sender, char *msg)
Definition handchat.c:280
static void chat_msg_to_allies(struct connection *sender, char *msg)
Definition handchat.c:222
static void chat_msg_to_global_observers(struct connection *sender, char *msg)
Definition handchat.c:254
void handle_chat_msg_req(struct connection *pconn, const char *message)
Definition handchat.c:320
static void chat_msg_to_conn(struct connection *sender, struct connection *dest, char *msg)
Definition handchat.c:127
const char * name
Definition inputfile.c:127
#define log_error(message,...)
Definition log.h:103
void package_chat_msg(struct packet_chat_msg *packet, const struct connection *sender, const struct ft_color color, const char *format,...)
Definition notify.c:123
void event_cache_add_for_players(const struct packet_chat_msg *packet, struct event_cache_players *players)
Definition notify.c:671
struct event_cache_players * event_cache_player_add(struct event_cache_players *players, const struct player *pplayer)
Definition notify.c:703
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:238
void event_cache_add_for_global_observers(const struct packet_chat_msg *packet)
Definition notify.c:630
void vpackage_chat_msg(struct packet_chat_msg *packet, const struct connection *sender, const struct ft_color color, const char *format, va_list vargs)
Definition notify.c:104
void event_cache_add_for_all(const struct packet_chat_msg *packet)
Definition notify.c:619
void lsend_packet_chat_msg(struct conn_list *dest, const struct packet_chat_msg *packet)
int send_packet_chat_msg(struct connection *pc, const struct packet_chat_msg *packet)
int len
Definition packhand.c:127
struct player * player_by_name_prefix(const char *name, enum m_pre_result *result)
Definition player.c:920
const char * player_name(const struct player *pplayer)
Definition player.c:895
bool pplayers_allied(const struct player *pplayer, const struct player *pplayer2)
Definition player.c:1405
#define players_iterate_end
Definition player.h:537
#define players_iterate(_pplayer)
Definition player.h:532
#define ANON_PLAYER_NAME
Definition player.h:43
char * skip_leading_spaces(char *s)
Definition shared.c:388
#define MIN(x, y)
Definition shared.h:55
m_pre_result
Definition shared.h:207
@ M_PRE_AMBIGUOUS
Definition shared.h:210
bool handle_stdin_input(struct connection *caller, char *str)
Definition stdinhand.c:4429
struct conn_list * est_connections
Definition game.h:97
Definition colors.h:21
char message[MAX_LEN_MSG]
int fc_snprintf(char *str, size_t n, const char *format,...)
Definition support.c:974
size_t fc_strlcpy(char *dest, const char *src, size_t n)
Definition support.c:791
#define sz_strlcpy(dest, src)
Definition support.h:195
#define fc__attribute(x)
Definition support.h:99
#define FALSE
Definition support.h:47