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.8 2000/07/19 07:06:51 priikone
30 * Revision 1.7 2000/07/12 05:56:32 priikone
31 * Major rewrite of ID Cache system. Support added for the new
34 * Revision 1.6 2000/07/10 05:38:32 priikone
37 * Revision 1.5 2000/07/06 07:14:36 priikone
38 * Fixes to NAMES command handling.
39 * Fixes when leaving from channel.
41 * Revision 1.4 2000/07/05 06:12:34 priikone
42 * Tweaked NAMES command reply for better. Should now show users
43 * joined to a channel.
45 * Revision 1.3 2000/07/04 08:27:14 priikone
46 * Changes to LEAVE command -- more consistent now and does error
47 * handling better. Added INVITE, PING and part of NAMES commands.
48 * SilcPacketContext is included into command structure.
50 * Revision 1.2 2000/07/03 05:49:49 priikone
51 * Implemented LEAVE command. Minor bug fixes.
53 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
54 * Imported from internal CVS/Added Log headers.
59 #include "clientincludes.h"
61 /* Client command reply list. */
62 SilcClientCommandReply silc_command_reply_list[] =
64 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
65 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
66 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
67 SILC_CLIENT_CMD_REPLY(nick, NICK),
68 SILC_CLIENT_CMD_REPLY(list, LIST),
69 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
70 SILC_CLIENT_CMD_REPLY(invite, INVITE),
71 SILC_CLIENT_CMD_REPLY(quit, QUIT),
72 SILC_CLIENT_CMD_REPLY(kill, KILL),
73 SILC_CLIENT_CMD_REPLY(info, INFO),
74 SILC_CLIENT_CMD_REPLY(away, AWAY),
75 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
76 SILC_CLIENT_CMD_REPLY(ping, PING),
77 SILC_CLIENT_CMD_REPLY(oper, OPER),
78 SILC_CLIENT_CMD_REPLY(join, JOIN),
79 SILC_CLIENT_CMD_REPLY(motd, MOTD),
80 SILC_CLIENT_CMD_REPLY(umode, UMODE),
81 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
82 SILC_CLIENT_CMD_REPLY(kick, KICK),
83 SILC_CLIENT_CMD_REPLY(restart, RESTART),
84 SILC_CLIENT_CMD_REPLY(close, CLOSE),
85 SILC_CLIENT_CMD_REPLY(die, DIE),
86 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
87 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
88 SILC_CLIENT_CMD_REPLY(names, NAMES),
93 /* Status message structure. Messages are defined below. */
95 SilcCommandStatus status;
97 } SilcCommandStatusMessage;
99 /* Status messages returned by the server */
100 #define STAT(x) SILC_STATUS_ERR_##x
101 const SilcCommandStatusMessage silc_command_status_messages[] = {
103 { STAT(NO_SUCH_NICK), "No such nickname" },
104 { STAT(NO_SUCH_CHANNEL), "No such channel" },
105 { STAT(NO_SUCH_SERVER), "No such server" },
106 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
107 { STAT(NO_RECIPIENT), "No recipient given" },
108 { STAT(UNKNOWN_COMMAND), "Unknown command" },
109 { STAT(WILDCARDS), "Unknown command" },
110 { STAT(NO_CLIENT_ID), "No Client ID given" },
111 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
112 { STAT(NO_SERVER_ID), "No Server ID given" },
113 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
114 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
115 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
116 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
117 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
118 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
119 { STAT(USER_ON_CHANNEL), "User already on channel" },
120 { STAT(NOT_REGISTERED), "You have not registered" },
121 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
122 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
123 { STAT(PERM_DENIED), "Your host is not among the privileged" },
124 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
125 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
126 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
127 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
128 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
129 { STAT(UNKNOWN_MODE), "Unknown mode" },
130 { STAT(NOT_YOU), "Cannot change mode for other users" },
131 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
132 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
133 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
134 { STAT(BAD_NICKNAME), "Bad nickname" },
135 { STAT(BAD_CHANNEL), "Bad channel name" },
136 { STAT(AUTH_FAILED), "Authentication failed" },
141 /* Process received command reply. */
143 void silc_client_command_reply_process(SilcClient client,
144 SilcSocketConnection sock,
145 SilcPacketContext *packet)
147 SilcBuffer buffer = packet->buffer;
148 SilcClientCommandReplyContext ctx;
149 SilcCommandPayload payload;
151 /* Get command reply payload from packet */
152 payload = silc_command_parse_payload(buffer);
154 /* Silently ignore bad reply packet */
155 SILC_LOG_DEBUG(("Bad command reply packet"));
159 /* Allocate command reply context. This must be free'd by the
160 command reply routine receiving it. */
161 ctx = silc_calloc(1, sizeof(*ctx));
162 ctx->client = client;
164 ctx->payload = payload;
165 ctx->packet = packet;
167 /* Check for pending commands and mark to be exeucted */
168 SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
170 /* Execute command reply */
171 SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
174 /* Returns status message string */
177 silc_client_command_status_message(SilcCommandStatus status)
181 for (i = 0; silc_command_status_messages[i].message; i++) {
182 if (silc_command_status_messages[i].status == status)
186 if (silc_command_status_messages[i].message == NULL)
189 return silc_command_status_messages[i].message;
192 /* Free command reply context and its internals. */
194 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
197 silc_command_free_payload(cmd->payload);
202 /* Received reply for WHOIS command. This maybe called several times
203 for one WHOIS command as server may reply with list of results. */
205 SILC_CLIENT_CMD_REPLY_FUNC(whois)
207 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
208 SilcCommandStatus status;
211 SILC_LOG_DEBUG(("Start"));
213 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
214 SILC_GET16_MSB(status, tmp);
215 if (status != SILC_STATUS_OK) {
216 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
217 /* Take nickname which may be provided */
218 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
220 silc_say(cmd->client, "%s: %s", tmp,
221 silc_client_command_status_message(status));
223 silc_say(cmd->client, "%s",
224 silc_client_command_status_message(status));
227 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
232 /* Display one whois reply */
233 if (status == SILC_STATUS_OK) {
236 unsigned char *id_data;
237 char *nickname = NULL, *username = NULL;
238 char *realname = NULL;
240 memset(buf, 0, sizeof(buf));
242 argc = silc_command_get_arg_num(cmd->payload);
243 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
245 nickname = silc_command_get_arg_type(cmd->payload, 3, &len);
247 strncat(buf, nickname, len);
248 strncat(buf, " is ", 4);
251 username = silc_command_get_arg_type(cmd->payload, 4, &len);
253 strncat(buf, username, len);
256 realname = silc_command_get_arg_type(cmd->payload, 5, &len);
258 strncat(buf, " (", 2);
259 strncat(buf, realname, len);
260 strncat(buf, ")", 1);
264 /* Save received Client ID to ID cache */
265 /* XXX Maybe should not be saved as /MSG will get confused */
266 id = silc_id_str2id(id_data, SILC_ID_CLIENT);
267 client->current_win->client_id_cache_count[(int)nickname[0] - 32] =
268 silc_idcache_add(&client->current_win->
269 client_id_cache[(int)nickname[0] - 32],
270 client->current_win->
271 client_id_cache_count[(int)nickname[0] - 32],
272 strdup(nickname), SILC_ID_CLIENT, id, NULL);
275 silc_say(cmd->client, "%s", buf);
278 if (status == SILC_STATUS_LIST_START) {
282 if (status == SILC_STATUS_LIST_END) {
286 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
289 silc_client_command_reply_free(cmd);
292 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
296 /* Received reply for IDENTIFY command. This maybe called several times
297 for one IDENTIFY command as server may reply with list of results.
298 This is totally silent and does not print anything on screen. */
300 SILC_CLIENT_CMD_REPLY_FUNC(identify)
302 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
303 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
304 SilcClientEntry client_entry;
305 SilcCommandStatus status;
308 SILC_LOG_DEBUG(("Start"));
310 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
311 SILC_GET16_MSB(status, tmp);
312 if (status != SILC_STATUS_OK) {
313 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
314 /* Take nickname which may be provided */
315 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
317 silc_say(cmd->client, "%s: %s", tmp,
318 silc_client_command_status_message(status));
320 silc_say(cmd->client, "%s",
321 silc_client_command_status_message(status));
324 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
329 /* Display one whois reply */
330 if (status == SILC_STATUS_OK) {
331 unsigned char *id_data;
334 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
335 nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
337 /* Allocate client entry */
338 client_entry = silc_calloc(1, sizeof(*client_entry));
339 client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
340 client_entry->nickname = strdup(nickname);
342 /* Save received Client ID to ID cache */
343 silc_idcache_add(win->client_cache, client_entry->nickname,
344 SILC_ID_CLIENT, client_entry->id, client_entry, TRUE);
347 if (status == SILC_STATUS_LIST_START) {
351 if (status == SILC_STATUS_LIST_END) {
355 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
358 silc_client_command_reply_free(cmd);
361 /* Received reply for command NICK. If everything went without errors
362 we just received our new Client ID. */
364 SILC_CLIENT_CMD_REPLY_FUNC(nick)
366 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
367 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
368 SilcCommandStatus status;
369 unsigned char *tmp, *id_string;
372 SILC_LOG_DEBUG(("Start"));
374 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
375 SILC_GET16_MSB(status, tmp);
376 if (status != SILC_STATUS_OK) {
377 silc_say(cmd->client, "Cannot set nickname: %s",
378 silc_client_command_status_message(status));
382 argc = silc_command_get_arg_num(cmd->payload);
383 if (argc < 2 || argc > 2) {
384 silc_say(cmd->client, "Cannot set nickname: bad reply to command");
388 /* Take received Client ID */
389 id_string = silc_command_get_arg_type(cmd->payload, 2, NULL);
390 silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
392 /* Update nickname on screen */
393 cmd->client->screen->bottom_line->nickname = win->nickname;
394 silc_screen_print_bottom_line(cmd->client->screen, 0);
397 silc_client_command_reply_free(cmd);
400 SILC_CLIENT_CMD_REPLY_FUNC(list)
404 SILC_CLIENT_CMD_REPLY_FUNC(topic)
408 /* Received reply to invite command. */
410 SILC_CLIENT_CMD_REPLY_FUNC(invite)
412 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
413 SilcCommandStatus status;
416 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
417 SILC_GET16_MSB(status, tmp);
418 if (status != SILC_STATUS_OK) {
419 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
420 silc_client_command_reply_free(cmd);
424 silc_client_command_reply_free(cmd);
427 SILC_CLIENT_CMD_REPLY_FUNC(quit)
431 SILC_CLIENT_CMD_REPLY_FUNC(kill)
435 /* Received reply to INFO command. We receive the server ID and some
436 information about the server user requested. */
438 SILC_CLIENT_CMD_REPLY_FUNC(info)
440 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
441 SilcClient client = cmd->client;
442 SilcCommandStatus status;
445 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
446 SILC_GET16_MSB(status, tmp);
447 if (status != SILC_STATUS_OK) {
448 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
449 silc_client_command_reply_free(cmd);
454 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
458 /* XXX save server id */
460 /* Get server info */
461 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
465 silc_say(client, "Info: %s", tmp);
468 silc_client_command_reply_free(cmd);
471 SILC_CLIENT_CMD_REPLY_FUNC(away)
475 SILC_CLIENT_CMD_REPLY_FUNC(connect)
479 /* Received reply to PING command. The reply time is shown to user. */
481 SILC_CLIENT_CMD_REPLY_FUNC(ping)
483 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
484 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
485 SilcCommandStatus status;
489 time_t diff, curtime;
491 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
492 SILC_GET16_MSB(status, tmp);
493 if (status != SILC_STATUS_OK) {
494 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
498 curtime = time(NULL);
499 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
501 for (i = 0; i < win->ping_count; i++) {
502 if (!SILC_ID_SERVER_COMPARE(win->ping[i].dest_id, id)) {
503 diff = curtime - win->ping[i].start_time;
504 silc_say(cmd->client, "Ping reply from %s: %d second%s",
505 win->ping[i].dest_name, diff, diff == 1 ? "" : "s");
507 win->ping[i].start_time = 0;
508 silc_free(win->ping[i].dest_id);
509 win->ping[i].dest_id = NULL;
510 silc_free(win->ping[i].dest_name);
511 win->ping[i].dest_name = NULL;
517 silc_client_command_reply_free(cmd);
520 SILC_CLIENT_CMD_REPLY_FUNC(oper)
524 /* Received reply for JOIN command. */
526 SILC_CLIENT_CMD_REPLY_FUNC(join)
528 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
529 SilcClient client = cmd->client;
530 SilcCommandStatus status;
531 unsigned int argc, mode;
532 unsigned char *id_string;
533 char *topic, *tmp, *channel_name;
535 SILC_LOG_DEBUG(("Start"));
537 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
538 SILC_GET16_MSB(status, tmp);
539 if (status != SILC_STATUS_OK) {
540 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
544 argc = silc_command_get_arg_num(cmd->payload);
545 if (argc < 3 || argc > 4) {
546 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
550 /* Get channel name */
551 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
553 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
556 channel_name = strdup(tmp);
559 id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
561 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
565 /* Get channel mode */
566 tmp = silc_command_get_arg_type(cmd->payload, 4, NULL);
568 SILC_GET32_MSB(mode, tmp);
573 topic = silc_command_get_arg_type(cmd->payload, 5, NULL);
575 /* Save received Channel ID */
576 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
579 /* Print channel name on screen */
580 client->screen->bottom_line->channel = channel_name;
581 silc_screen_print_bottom_line(client->screen, 0);
584 silc_say(client, "Topic for %s: %s", channel_name, topic);
587 silc_client_command_reply_free(cmd);
590 SILC_CLIENT_CMD_REPLY_FUNC(motd)
594 SILC_CLIENT_CMD_REPLY_FUNC(umode)
598 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
602 SILC_CLIENT_CMD_REPLY_FUNC(kick)
606 SILC_CLIENT_CMD_REPLY_FUNC(restart)
610 SILC_CLIENT_CMD_REPLY_FUNC(close)
614 SILC_CLIENT_CMD_REPLY_FUNC(die)
618 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
622 /* Reply to LEAVE command. */
624 SILC_CLIENT_CMD_REPLY_FUNC(leave)
626 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
627 SilcCommandStatus status;
630 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
631 SILC_GET16_MSB(status, tmp);
632 if (status != SILC_STATUS_OK)
633 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
635 silc_client_command_reply_free(cmd);
638 /* Reply to NAMES command. Received list of client names on the channel
641 SILC_CLIENT_CMD_REPLY_FUNC(names)
643 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
644 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
645 SilcCommandStatus status;
646 SilcIDCacheEntry id_cache = NULL;
647 SilcChannelEntry channel;
648 SilcChannelID *channel_id = NULL;
649 SilcBuffer client_id_list;
652 int i, len1, len2, list_count = 0;
654 SILC_LOG_DEBUG(("Start"));
656 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
657 SILC_GET16_MSB(status, tmp);
658 if (status != SILC_STATUS_OK) {
659 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
664 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
666 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
669 channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
671 /* Get the name list of the channel */
672 name_list = silc_command_get_arg_type(cmd->payload, 3, &len1);
674 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
678 /* Get Client ID list */
679 tmp = silc_command_get_arg_type(cmd->payload, 4, &len2);
681 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
685 client_id_list = silc_buffer_alloc(len2);
686 silc_buffer_pull_tail(client_id_list, len2);
687 silc_buffer_put(client_id_list, tmp, len2);
689 /* Get the channel name */
690 if (!silc_idcache_find_by_id_one(win->channel_cache, (void *)channel_id,
691 SILC_ID_CHANNEL, &id_cache))
694 channel = (SilcChannelEntry)id_cache->context;
696 /* If there is pending command we know that user has called this command
697 and we will handle the name list differently. */
699 /* We will resolve all the necessary information about the people
700 on the channel. Only after that will we display the user list. */
701 for (i = 0; i < len1; i++) {
705 silc_client_command_pending_del(SILC_COMMAND_NAMES);
707 /* there is no pending callback it means that this command reply
708 has been received without calling the command, ie. server has sent
709 the reply without getting the command from us first. This happens
710 with SILC servers that sends NAMES reply after joining to a channel. */
712 /* Remove commas from list */
713 for (i = 0; i < len1; i++)
714 if (name_list[i] == ',') {
719 silc_say(cmd->client, "Users on %s: %s", channel->channel_name, name_list);
722 /* Cache the received name list and client ID's. This cache expires
723 whenever server sends notify message to channel. It means two things;
724 some user has joined or leaved the channel. */
725 for (i = 0; i < list_count; i++) {
726 int nick_len = strcspn(name_list, " ");
727 char *nickname = silc_calloc(nick_len, sizeof(*nickname));
728 SilcClientID *client_id;
729 SilcClientEntry client;
731 memcpy(nickname, name_list, nick_len);
732 client_id = silc_id_str2id(client_id_list->data, SILC_ID_CLIENT_LEN);
733 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
735 client = silc_calloc(1, sizeof(*client));
736 client->id = client_id;
737 client->nickname = nickname;
739 silc_idcache_add(win->client_cache, nickname, SILC_ID_CLIENT,
740 client_id, (void *)client, TRUE);
741 name_list = name_list + nick_len + 1;
744 silc_buffer_free(client_id_list);
748 silc_free(channel_id);
749 silc_client_command_reply_free(cmd);
752 /* Private message received. This processes the private message and
753 finally displays it on the screen. Note that private messages are not
754 really commands except on user interface which is reason why this
755 handling resides here. */
757 SILC_CLIENT_CMD_REPLY_FUNC(msg)
759 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
760 SilcClient client = cmd->client;
761 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
762 SilcBuffer buffer = (SilcBuffer)cmd->packet->buffer;
763 unsigned short nick_len;
764 unsigned char *nickname, *message;
767 silc_buffer_unformat(buffer,
768 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
770 silc_buffer_pull(buffer, 2 + nick_len);
772 message = silc_calloc(buffer->len + 1, sizeof(char));
773 memcpy(message, buffer->data, buffer->len);
774 silc_print(client, "*%s* %s", nickname, message);
776 /* See if we are away (gone). If we are away we will reply to the
777 sender with the set away message. */
778 if (win->away && win->away->away) {
779 SilcClientID *remote_id;
780 SilcClientEntry remote_client;
781 SilcIDCacheEntry id_cache;
783 if (cmd->packet->src_id_type != SILC_ID_CLIENT)
786 remote_id = silc_id_str2id(cmd->packet->src_id, SILC_ID_CLIENT);
790 /* Check whether we know this client already */
791 if (!silc_idcache_find_by_id_one(win->client_cache, remote_id,
792 SILC_ID_CLIENT, &id_cache))
794 /* Allocate client entry */
795 remote_client = silc_calloc(1, sizeof(*remote_client));
796 remote_client->id = remote_id;
797 remote_client->nickname = strdup(nickname);
799 /* Save the client to cache */
800 silc_idcache_add(win->client_cache, remote_client->nickname,
801 SILC_ID_CLIENT, remote_client->id, remote_client,
804 silc_free(remote_id);
805 remote_client = (SilcClientEntry)id_cache->context;
808 /* Send the away message */
809 silc_client_packet_send_private_message(client, cmd->sock, remote_client,
811 strlen(win->away->away), TRUE);
815 memset(message, 0, buffer->len);