5 Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
7 Copyright (C) 1997 - 2000 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
21 * Command reply functions are "the otherside" of the command functions.
22 * Reply to a command sent by server is handled by these functions.
27 * Revision 1.9 2000/07/19 09:19:05 priikone
28 * Enhancements to AWAY command.
30 * Revision 1.8 2000/07/19 07:06:51 priikone
33 * Revision 1.7 2000/07/12 05:56:32 priikone
34 * Major rewrite of ID Cache system. Support added for the new
37 * Revision 1.6 2000/07/10 05:38:32 priikone
40 * Revision 1.5 2000/07/06 07:14:36 priikone
41 * Fixes to NAMES command handling.
42 * Fixes when leaving from channel.
44 * Revision 1.4 2000/07/05 06:12:34 priikone
45 * Tweaked NAMES command reply for better. Should now show users
46 * joined to a channel.
48 * Revision 1.3 2000/07/04 08:27:14 priikone
49 * Changes to LEAVE command -- more consistent now and does error
50 * handling better. Added INVITE, PING and part of NAMES commands.
51 * SilcPacketContext is included into command structure.
53 * Revision 1.2 2000/07/03 05:49:49 priikone
54 * Implemented LEAVE command. Minor bug fixes.
56 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
57 * Imported from internal CVS/Added Log headers.
62 #include "clientincludes.h"
64 /* Client command reply list. */
65 SilcClientCommandReply silc_command_reply_list[] =
67 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
68 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
69 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
70 SILC_CLIENT_CMD_REPLY(nick, NICK),
71 SILC_CLIENT_CMD_REPLY(list, LIST),
72 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
73 SILC_CLIENT_CMD_REPLY(invite, INVITE),
74 SILC_CLIENT_CMD_REPLY(quit, QUIT),
75 SILC_CLIENT_CMD_REPLY(kill, KILL),
76 SILC_CLIENT_CMD_REPLY(info, INFO),
77 SILC_CLIENT_CMD_REPLY(away, AWAY),
78 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
79 SILC_CLIENT_CMD_REPLY(ping, PING),
80 SILC_CLIENT_CMD_REPLY(oper, OPER),
81 SILC_CLIENT_CMD_REPLY(join, JOIN),
82 SILC_CLIENT_CMD_REPLY(motd, MOTD),
83 SILC_CLIENT_CMD_REPLY(umode, UMODE),
84 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
85 SILC_CLIENT_CMD_REPLY(kick, KICK),
86 SILC_CLIENT_CMD_REPLY(restart, RESTART),
87 SILC_CLIENT_CMD_REPLY(close, CLOSE),
88 SILC_CLIENT_CMD_REPLY(die, DIE),
89 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
90 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
91 SILC_CLIENT_CMD_REPLY(names, NAMES),
96 /* Status message structure. Messages are defined below. */
98 SilcCommandStatus status;
100 } SilcCommandStatusMessage;
102 /* Status messages returned by the server */
103 #define STAT(x) SILC_STATUS_ERR_##x
104 const SilcCommandStatusMessage silc_command_status_messages[] = {
106 { STAT(NO_SUCH_NICK), "No such nickname" },
107 { STAT(NO_SUCH_CHANNEL), "No such channel" },
108 { STAT(NO_SUCH_SERVER), "No such server" },
109 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
110 { STAT(NO_RECIPIENT), "No recipient given" },
111 { STAT(UNKNOWN_COMMAND), "Unknown command" },
112 { STAT(WILDCARDS), "Unknown command" },
113 { STAT(NO_CLIENT_ID), "No Client ID given" },
114 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
115 { STAT(NO_SERVER_ID), "No Server ID given" },
116 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
117 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
118 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
119 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
120 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
121 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
122 { STAT(USER_ON_CHANNEL), "User already on channel" },
123 { STAT(NOT_REGISTERED), "You have not registered" },
124 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
125 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
126 { STAT(PERM_DENIED), "Your host is not among the privileged" },
127 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
128 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
129 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
130 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
131 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
132 { STAT(UNKNOWN_MODE), "Unknown mode" },
133 { STAT(NOT_YOU), "Cannot change mode for other users" },
134 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
135 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
136 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
137 { STAT(BAD_NICKNAME), "Bad nickname" },
138 { STAT(BAD_CHANNEL), "Bad channel name" },
139 { STAT(AUTH_FAILED), "Authentication failed" },
144 /* Process received command reply. */
146 void silc_client_command_reply_process(SilcClient client,
147 SilcSocketConnection sock,
148 SilcPacketContext *packet)
150 SilcBuffer buffer = packet->buffer;
151 SilcClientCommandReplyContext ctx;
152 SilcCommandPayload payload;
154 /* Get command reply payload from packet */
155 payload = silc_command_parse_payload(buffer);
157 /* Silently ignore bad reply packet */
158 SILC_LOG_DEBUG(("Bad command reply packet"));
162 /* Allocate command reply context. This must be free'd by the
163 command reply routine receiving it. */
164 ctx = silc_calloc(1, sizeof(*ctx));
165 ctx->client = client;
167 ctx->payload = payload;
168 ctx->packet = packet;
170 /* Check for pending commands and mark to be exeucted */
171 SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
173 /* Execute command reply */
174 SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
177 /* Returns status message string */
180 silc_client_command_status_message(SilcCommandStatus status)
184 for (i = 0; silc_command_status_messages[i].message; i++) {
185 if (silc_command_status_messages[i].status == status)
189 if (silc_command_status_messages[i].message == NULL)
192 return silc_command_status_messages[i].message;
195 /* Free command reply context and its internals. */
197 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
200 silc_command_free_payload(cmd->payload);
205 /* Received reply for WHOIS command. This maybe called several times
206 for one WHOIS command as server may reply with list of results. */
208 SILC_CLIENT_CMD_REPLY_FUNC(whois)
210 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
211 SilcCommandStatus status;
214 SILC_LOG_DEBUG(("Start"));
216 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
217 SILC_GET16_MSB(status, tmp);
218 if (status != SILC_STATUS_OK) {
219 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
220 /* Take nickname which may be provided */
221 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
223 silc_say(cmd->client, "%s: %s", tmp,
224 silc_client_command_status_message(status));
226 silc_say(cmd->client, "%s",
227 silc_client_command_status_message(status));
230 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
235 /* Display one whois reply */
236 if (status == SILC_STATUS_OK) {
239 unsigned char *id_data;
240 char *nickname = NULL, *username = NULL;
241 char *realname = NULL;
243 memset(buf, 0, sizeof(buf));
245 argc = silc_command_get_arg_num(cmd->payload);
246 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
248 nickname = silc_command_get_arg_type(cmd->payload, 3, &len);
250 strncat(buf, nickname, len);
251 strncat(buf, " is ", 4);
254 username = silc_command_get_arg_type(cmd->payload, 4, &len);
256 strncat(buf, username, len);
259 realname = silc_command_get_arg_type(cmd->payload, 5, &len);
261 strncat(buf, " (", 2);
262 strncat(buf, realname, len);
263 strncat(buf, ")", 1);
267 /* Save received Client ID to ID cache */
268 /* XXX Maybe should not be saved as /MSG will get confused */
269 id = silc_id_str2id(id_data, SILC_ID_CLIENT);
270 client->current_win->client_id_cache_count[(int)nickname[0] - 32] =
271 silc_idcache_add(&client->current_win->
272 client_id_cache[(int)nickname[0] - 32],
273 client->current_win->
274 client_id_cache_count[(int)nickname[0] - 32],
275 strdup(nickname), SILC_ID_CLIENT, id, NULL);
278 silc_say(cmd->client, "%s", buf);
281 if (status == SILC_STATUS_LIST_START) {
285 if (status == SILC_STATUS_LIST_END) {
289 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
292 silc_client_command_reply_free(cmd);
295 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
299 /* Received reply for IDENTIFY command. This maybe called several times
300 for one IDENTIFY command as server may reply with list of results.
301 This is totally silent and does not print anything on screen. */
303 SILC_CLIENT_CMD_REPLY_FUNC(identify)
305 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
306 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
307 SilcClientEntry client_entry;
308 SilcCommandStatus status;
311 SILC_LOG_DEBUG(("Start"));
313 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
314 SILC_GET16_MSB(status, tmp);
315 if (status != SILC_STATUS_OK) {
316 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
317 /* Take nickname which may be provided */
318 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
320 silc_say(cmd->client, "%s: %s", tmp,
321 silc_client_command_status_message(status));
323 silc_say(cmd->client, "%s",
324 silc_client_command_status_message(status));
327 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
332 /* Display one whois reply */
333 if (status == SILC_STATUS_OK) {
334 unsigned char *id_data;
337 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
338 nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
340 /* Allocate client entry */
341 client_entry = silc_calloc(1, sizeof(*client_entry));
342 client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
343 client_entry->nickname = strdup(nickname);
345 /* Save received Client ID to ID cache */
346 silc_idcache_add(win->client_cache, client_entry->nickname,
347 SILC_ID_CLIENT, client_entry->id, client_entry, TRUE);
350 if (status == SILC_STATUS_LIST_START) {
354 if (status == SILC_STATUS_LIST_END) {
358 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
361 silc_client_command_reply_free(cmd);
364 /* Received reply for command NICK. If everything went without errors
365 we just received our new Client ID. */
367 SILC_CLIENT_CMD_REPLY_FUNC(nick)
369 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
370 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
371 SilcCommandStatus status;
372 unsigned char *tmp, *id_string;
375 SILC_LOG_DEBUG(("Start"));
377 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
378 SILC_GET16_MSB(status, tmp);
379 if (status != SILC_STATUS_OK) {
380 silc_say(cmd->client, "Cannot set nickname: %s",
381 silc_client_command_status_message(status));
385 argc = silc_command_get_arg_num(cmd->payload);
386 if (argc < 2 || argc > 2) {
387 silc_say(cmd->client, "Cannot set nickname: bad reply to command");
391 /* Take received Client ID */
392 id_string = silc_command_get_arg_type(cmd->payload, 2, NULL);
393 silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
395 /* Update nickname on screen */
396 cmd->client->screen->bottom_line->nickname = win->nickname;
397 silc_screen_print_bottom_line(cmd->client->screen, 0);
400 silc_client_command_reply_free(cmd);
403 SILC_CLIENT_CMD_REPLY_FUNC(list)
407 SILC_CLIENT_CMD_REPLY_FUNC(topic)
411 /* Received reply to invite command. */
413 SILC_CLIENT_CMD_REPLY_FUNC(invite)
415 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
416 SilcCommandStatus status;
419 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
420 SILC_GET16_MSB(status, tmp);
421 if (status != SILC_STATUS_OK) {
422 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
423 silc_client_command_reply_free(cmd);
427 silc_client_command_reply_free(cmd);
430 SILC_CLIENT_CMD_REPLY_FUNC(quit)
434 SILC_CLIENT_CMD_REPLY_FUNC(kill)
438 /* Received reply to INFO command. We receive the server ID and some
439 information about the server user requested. */
441 SILC_CLIENT_CMD_REPLY_FUNC(info)
443 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
444 SilcClient client = cmd->client;
445 SilcCommandStatus status;
448 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
449 SILC_GET16_MSB(status, tmp);
450 if (status != SILC_STATUS_OK) {
451 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
452 silc_client_command_reply_free(cmd);
457 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
461 /* XXX save server id */
463 /* Get server info */
464 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
468 silc_say(client, "Info: %s", tmp);
471 silc_client_command_reply_free(cmd);
474 SILC_CLIENT_CMD_REPLY_FUNC(away)
478 SILC_CLIENT_CMD_REPLY_FUNC(connect)
482 /* Received reply to PING command. The reply time is shown to user. */
484 SILC_CLIENT_CMD_REPLY_FUNC(ping)
486 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
487 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
488 SilcCommandStatus status;
492 time_t diff, curtime;
494 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
495 SILC_GET16_MSB(status, tmp);
496 if (status != SILC_STATUS_OK) {
497 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
501 curtime = time(NULL);
502 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
504 for (i = 0; i < win->ping_count; i++) {
505 if (!SILC_ID_SERVER_COMPARE(win->ping[i].dest_id, id)) {
506 diff = curtime - win->ping[i].start_time;
507 silc_say(cmd->client, "Ping reply from %s: %d second%s",
508 win->ping[i].dest_name, diff, diff == 1 ? "" : "s");
510 win->ping[i].start_time = 0;
511 silc_free(win->ping[i].dest_id);
512 win->ping[i].dest_id = NULL;
513 silc_free(win->ping[i].dest_name);
514 win->ping[i].dest_name = NULL;
520 silc_client_command_reply_free(cmd);
523 SILC_CLIENT_CMD_REPLY_FUNC(oper)
527 /* Received reply for JOIN command. */
529 SILC_CLIENT_CMD_REPLY_FUNC(join)
531 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
532 SilcClient client = cmd->client;
533 SilcCommandStatus status;
534 unsigned int argc, mode;
535 unsigned char *id_string;
536 char *topic, *tmp, *channel_name;
538 SILC_LOG_DEBUG(("Start"));
540 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
541 SILC_GET16_MSB(status, tmp);
542 if (status != SILC_STATUS_OK) {
543 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
547 argc = silc_command_get_arg_num(cmd->payload);
548 if (argc < 3 || argc > 4) {
549 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
553 /* Get channel name */
554 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
556 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
559 channel_name = strdup(tmp);
562 id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
564 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
568 /* Get channel mode */
569 tmp = silc_command_get_arg_type(cmd->payload, 4, NULL);
571 SILC_GET32_MSB(mode, tmp);
576 topic = silc_command_get_arg_type(cmd->payload, 5, NULL);
578 /* Save received Channel ID */
579 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
582 /* Print channel name on screen */
583 client->screen->bottom_line->channel = channel_name;
584 silc_screen_print_bottom_line(client->screen, 0);
587 silc_say(client, "Topic for %s: %s", channel_name, topic);
590 silc_client_command_reply_free(cmd);
593 SILC_CLIENT_CMD_REPLY_FUNC(motd)
597 SILC_CLIENT_CMD_REPLY_FUNC(umode)
601 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
605 SILC_CLIENT_CMD_REPLY_FUNC(kick)
609 SILC_CLIENT_CMD_REPLY_FUNC(restart)
613 SILC_CLIENT_CMD_REPLY_FUNC(close)
617 SILC_CLIENT_CMD_REPLY_FUNC(die)
621 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
625 /* Reply to LEAVE command. */
627 SILC_CLIENT_CMD_REPLY_FUNC(leave)
629 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
630 SilcCommandStatus status;
633 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
634 SILC_GET16_MSB(status, tmp);
635 if (status != SILC_STATUS_OK)
636 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
638 silc_client_command_reply_free(cmd);
641 /* Reply to NAMES command. Received list of client names on the channel
644 SILC_CLIENT_CMD_REPLY_FUNC(names)
646 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
647 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
648 SilcCommandStatus status;
649 SilcIDCacheEntry id_cache = NULL;
650 SilcChannelEntry channel;
651 SilcChannelID *channel_id = NULL;
652 SilcBuffer client_id_list;
655 int i, len1, len2, list_count = 0;
657 SILC_LOG_DEBUG(("Start"));
659 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
660 SILC_GET16_MSB(status, tmp);
661 if (status != SILC_STATUS_OK) {
662 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
667 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
669 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
672 channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
674 /* Get the name list of the channel */
675 name_list = silc_command_get_arg_type(cmd->payload, 3, &len1);
677 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
681 /* Get Client ID list */
682 tmp = silc_command_get_arg_type(cmd->payload, 4, &len2);
684 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
688 client_id_list = silc_buffer_alloc(len2);
689 silc_buffer_pull_tail(client_id_list, len2);
690 silc_buffer_put(client_id_list, tmp, len2);
692 /* Get the channel name */
693 if (!silc_idcache_find_by_id_one(win->channel_cache, (void *)channel_id,
694 SILC_ID_CHANNEL, &id_cache))
697 channel = (SilcChannelEntry)id_cache->context;
699 /* If there is pending command we know that user has called this command
700 and we will handle the name list differently. */
702 /* We will resolve all the necessary information about the people
703 on the channel. Only after that will we display the user list. */
704 for (i = 0; i < len1; i++) {
708 silc_client_command_pending_del(SILC_COMMAND_NAMES);
710 /* there is no pending callback it means that this command reply
711 has been received without calling the command, ie. server has sent
712 the reply without getting the command from us first. This happens
713 with SILC servers that sends NAMES reply after joining to a channel. */
715 /* Remove commas from list */
716 for (i = 0; i < len1; i++)
717 if (name_list[i] == ',') {
722 silc_say(cmd->client, "Users on %s: %s", channel->channel_name, name_list);
725 /* Cache the received name list and client ID's. This cache expires
726 whenever server sends notify message to channel. It means two things;
727 some user has joined or leaved the channel. */
728 for (i = 0; i < list_count; i++) {
729 int nick_len = strcspn(name_list, " ");
730 char *nickname = silc_calloc(nick_len, sizeof(*nickname));
731 SilcClientID *client_id;
732 SilcClientEntry client;
734 memcpy(nickname, name_list, nick_len);
735 client_id = silc_id_str2id(client_id_list->data, SILC_ID_CLIENT_LEN);
736 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
738 client = silc_calloc(1, sizeof(*client));
739 client->id = client_id;
740 client->nickname = nickname;
742 silc_idcache_add(win->client_cache, nickname, SILC_ID_CLIENT,
743 client_id, (void *)client, TRUE);
744 name_list = name_list + nick_len + 1;
747 silc_buffer_free(client_id_list);
751 silc_free(channel_id);
752 silc_client_command_reply_free(cmd);
755 /* Private message received. This processes the private message and
756 finally displays it on the screen. Note that private messages are not
757 really commands except on user interface which is reason why this
758 handling resides here. */
760 SILC_CLIENT_CMD_REPLY_FUNC(msg)
762 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
763 SilcClient client = cmd->client;
764 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
765 SilcBuffer buffer = (SilcBuffer)cmd->packet->buffer;
766 unsigned short nick_len;
767 unsigned char *nickname, *message;
770 silc_buffer_unformat(buffer,
771 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
773 silc_buffer_pull(buffer, 2 + nick_len);
775 message = silc_calloc(buffer->len + 1, sizeof(char));
776 memcpy(message, buffer->data, buffer->len);
777 silc_print(client, "*%s* %s", nickname, message);
779 /* See if we are away (gone). If we are away we will reply to the
780 sender with the set away message. */
781 if (win->away && win->away->away) {
782 SilcClientID *remote_id;
783 SilcClientEntry remote_client;
784 SilcIDCacheEntry id_cache;
786 if (cmd->packet->src_id_type != SILC_ID_CLIENT)
789 remote_id = silc_id_str2id(cmd->packet->src_id, SILC_ID_CLIENT);
793 if (!SILC_ID_CLIENT_COMPARE(remote_id, win->local_id))
796 /* Check whether we know this client already */
797 if (!silc_idcache_find_by_id_one(win->client_cache, remote_id,
798 SILC_ID_CLIENT, &id_cache))
800 /* Allocate client entry */
801 remote_client = silc_calloc(1, sizeof(*remote_client));
802 remote_client->id = remote_id;
803 remote_client->nickname = strdup(nickname);
805 /* Save the client to cache */
806 silc_idcache_add(win->client_cache, remote_client->nickname,
807 SILC_ID_CLIENT, remote_client->id, remote_client,
810 silc_free(remote_id);
811 remote_client = (SilcClientEntry)id_cache->context;
814 /* Send the away message */
815 silc_client_packet_send_private_message(client, cmd->sock, remote_client,
817 strlen(win->away->away), TRUE);
821 memset(message, 0, buffer->len);