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.7 2000/07/12 05:56:32 priikone
28 * Major rewrite of ID Cache system. Support added for the new
31 * Revision 1.6 2000/07/10 05:38:32 priikone
34 * Revision 1.5 2000/07/06 07:14:36 priikone
35 * Fixes to NAMES command handling.
36 * Fixes when leaving from channel.
38 * Revision 1.4 2000/07/05 06:12:34 priikone
39 * Tweaked NAMES command reply for better. Should now show users
40 * joined to a channel.
42 * Revision 1.3 2000/07/04 08:27:14 priikone
43 * Changes to LEAVE command -- more consistent now and does error
44 * handling better. Added INVITE, PING and part of NAMES commands.
45 * SilcPacketContext is included into command structure.
47 * Revision 1.2 2000/07/03 05:49:49 priikone
48 * Implemented LEAVE command. Minor bug fixes.
50 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
51 * Imported from internal CVS/Added Log headers.
56 #include "clientincludes.h"
58 /* Client command reply list. */
59 SilcClientCommandReply silc_command_reply_list[] =
61 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
62 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
63 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
64 SILC_CLIENT_CMD_REPLY(nick, NICK),
65 SILC_CLIENT_CMD_REPLY(list, LIST),
66 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
67 SILC_CLIENT_CMD_REPLY(invite, INVITE),
68 SILC_CLIENT_CMD_REPLY(quit, QUIT),
69 SILC_CLIENT_CMD_REPLY(kill, KILL),
70 SILC_CLIENT_CMD_REPLY(info, INFO),
71 SILC_CLIENT_CMD_REPLY(away, AWAY),
72 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
73 SILC_CLIENT_CMD_REPLY(ping, PING),
74 SILC_CLIENT_CMD_REPLY(oper, OPER),
75 SILC_CLIENT_CMD_REPLY(join, JOIN),
76 SILC_CLIENT_CMD_REPLY(motd, MOTD),
77 SILC_CLIENT_CMD_REPLY(umode, UMODE),
78 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
79 SILC_CLIENT_CMD_REPLY(kick, KICK),
80 SILC_CLIENT_CMD_REPLY(restart, RESTART),
81 SILC_CLIENT_CMD_REPLY(close, CLOSE),
82 SILC_CLIENT_CMD_REPLY(die, DIE),
83 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
84 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
85 SILC_CLIENT_CMD_REPLY(names, NAMES),
90 /* Status message structure. Messages are defined below. */
92 SilcCommandStatus status;
94 } SilcCommandStatusMessage;
96 /* Status messages returned by the server */
97 #define STAT(x) SILC_STATUS_ERR_##x
98 const SilcCommandStatusMessage silc_command_status_messages[] = {
100 { STAT(NO_SUCH_NICK), "No such nickname" },
101 { STAT(NO_SUCH_CHANNEL), "No such channel" },
102 { STAT(NO_SUCH_SERVER), "No such server" },
103 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
104 { STAT(NO_RECIPIENT), "No recipient given" },
105 { STAT(UNKNOWN_COMMAND), "Unknown command" },
106 { STAT(WILDCARDS), "Unknown command" },
107 { STAT(NO_CLIENT_ID), "No Client ID given" },
108 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
109 { STAT(NO_SERVER_ID), "No Server ID given" },
110 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
111 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
112 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
113 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
114 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
115 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
116 { STAT(USER_ON_CHANNEL), "User already on channel" },
117 { STAT(NOT_REGISTERED), "You have not registered" },
118 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
119 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
120 { STAT(PERM_DENIED), "Your host is not among the privileged" },
121 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
122 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
123 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
124 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
125 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
126 { STAT(UNKNOWN_MODE), "Unknown mode" },
127 { STAT(NOT_YOU), "Cannot change mode for other users" },
128 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
129 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
130 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
131 { STAT(BAD_NICKNAME), "Bad nickname" },
132 { STAT(BAD_CHANNEL), "Bad channel name" },
133 { STAT(AUTH_FAILED), "Authentication failed" },
138 /* Process received command reply. */
140 void silc_client_command_reply_process(SilcClient client,
141 SilcSocketConnection sock,
142 SilcPacketContext *packet)
144 SilcBuffer buffer = packet->buffer;
145 SilcClientCommandReplyContext ctx;
146 SilcCommandPayload payload;
148 /* Get command reply payload from packet */
149 payload = silc_command_parse_payload(buffer);
151 /* Silently ignore bad reply packet */
152 SILC_LOG_DEBUG(("Bad command reply packet"));
156 /* Allocate command reply context. This must be free'd by the
157 command reply routine receiving it. */
158 ctx = silc_calloc(1, sizeof(*ctx));
159 ctx->client = client;
161 ctx->payload = payload;
162 ctx->packet = packet;
164 /* Check for pending commands and mark to be exeucted */
165 SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
167 /* Execute command reply */
168 SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
171 /* Returns status message string */
174 silc_client_command_status_message(SilcCommandStatus status)
178 for (i = 0; silc_command_status_messages[i].message; i++) {
179 if (silc_command_status_messages[i].status == status)
183 if (silc_command_status_messages[i].message == NULL)
186 return silc_command_status_messages[i].message;
189 /* Free command reply context and its internals. */
191 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
194 silc_command_free_payload(cmd->payload);
199 /* Received reply for WHOIS command. This maybe called several times
200 for one WHOIS command as server may reply with list of results. */
202 SILC_CLIENT_CMD_REPLY_FUNC(whois)
204 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
205 SilcCommandStatus status;
208 SILC_LOG_DEBUG(("Start"));
210 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
211 SILC_GET16_MSB(status, tmp);
212 if (status != SILC_STATUS_OK) {
213 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
214 /* Take nickname which may be provided */
215 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
217 silc_say(cmd->client, "%s: %s", tmp,
218 silc_client_command_status_message(status));
220 silc_say(cmd->client, "%s",
221 silc_client_command_status_message(status));
224 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
229 /* Display one whois reply */
230 if (status == SILC_STATUS_OK) {
233 unsigned char *id_data;
234 char *nickname = NULL, *username = NULL;
235 char *realname = NULL;
237 memset(buf, 0, sizeof(buf));
239 argc = silc_command_get_arg_num(cmd->payload);
240 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
242 nickname = silc_command_get_arg_type(cmd->payload, 3, &len);
244 strncat(buf, nickname, len);
245 strncat(buf, " is ", 4);
248 username = silc_command_get_arg_type(cmd->payload, 4, &len);
250 strncat(buf, username, len);
253 realname = silc_command_get_arg_type(cmd->payload, 5, &len);
255 strncat(buf, " (", 2);
256 strncat(buf, realname, len);
257 strncat(buf, ")", 1);
261 /* Save received Client ID to ID cache */
262 /* XXX Maybe should not be saved as /MSG will get confused */
263 id = silc_id_str2id(id_data, SILC_ID_CLIENT);
264 client->current_win->client_id_cache_count[(int)nickname[0] - 32] =
265 silc_idcache_add(&client->current_win->
266 client_id_cache[(int)nickname[0] - 32],
267 client->current_win->
268 client_id_cache_count[(int)nickname[0] - 32],
269 strdup(nickname), SILC_ID_CLIENT, id, NULL);
272 silc_say(cmd->client, "%s", buf);
275 if (status == SILC_STATUS_LIST_START) {
279 if (status == SILC_STATUS_LIST_END) {
283 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
286 silc_client_command_reply_free(cmd);
289 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
293 /* Received reply for IDENTIFY command. This maybe called several times
294 for one IDENTIFY command as server may reply with list of results.
295 This is totally silent and does not print anything on screen. */
297 SILC_CLIENT_CMD_REPLY_FUNC(identify)
299 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
300 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
301 SilcClientEntry client_entry;
302 SilcCommandStatus status;
305 SILC_LOG_DEBUG(("Start"));
307 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
308 SILC_GET16_MSB(status, tmp);
309 if (status != SILC_STATUS_OK) {
310 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
311 /* Take nickname which may be provided */
312 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
314 silc_say(cmd->client, "%s: %s", tmp,
315 silc_client_command_status_message(status));
317 silc_say(cmd->client, "%s",
318 silc_client_command_status_message(status));
321 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
326 /* Display one whois reply */
327 if (status == SILC_STATUS_OK) {
328 unsigned char *id_data;
331 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
332 nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
334 /* Allocate client entry */
335 client_entry = silc_calloc(1, sizeof(*client_entry));
336 client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
337 client_entry->nickname = strdup(nickname);
339 /* Save received Client ID to ID cache */
340 silc_idcache_add(win->client_cache, client_entry->nickname,
341 SILC_ID_CLIENT, client_entry->id, client_entry, TRUE);
344 if (status == SILC_STATUS_LIST_START) {
348 if (status == SILC_STATUS_LIST_END) {
352 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
355 silc_client_command_reply_free(cmd);
358 /* Received reply for command NICK. If everything went without errors
359 we just received our new Client ID. */
361 SILC_CLIENT_CMD_REPLY_FUNC(nick)
363 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
364 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
365 SilcCommandStatus status;
366 unsigned char *tmp, *id_string;
369 SILC_LOG_DEBUG(("Start"));
371 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
372 SILC_GET16_MSB(status, tmp);
373 if (status != SILC_STATUS_OK) {
374 silc_say(cmd->client, "Cannot set nickname: %s",
375 silc_client_command_status_message(status));
379 argc = silc_command_get_arg_num(cmd->payload);
380 if (argc < 2 || argc > 2) {
381 silc_say(cmd->client, "Cannot set nickname: bad reply to command");
385 /* Take received Client ID */
386 id_string = silc_command_get_arg_type(cmd->payload, 2, NULL);
387 silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
389 /* Update nickname on screen */
390 cmd->client->screen->bottom_line->nickname = win->nickname;
391 silc_screen_print_bottom_line(cmd->client->screen, 0);
394 silc_client_command_reply_free(cmd);
397 SILC_CLIENT_CMD_REPLY_FUNC(list)
401 SILC_CLIENT_CMD_REPLY_FUNC(topic)
405 /* Received reply to invite command. */
407 SILC_CLIENT_CMD_REPLY_FUNC(invite)
409 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
410 SilcCommandStatus status;
413 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
414 SILC_GET16_MSB(status, tmp);
415 if (status != SILC_STATUS_OK) {
416 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
417 silc_client_command_reply_free(cmd);
421 silc_client_command_reply_free(cmd);
424 SILC_CLIENT_CMD_REPLY_FUNC(quit)
428 SILC_CLIENT_CMD_REPLY_FUNC(kill)
432 /* Received reply to INFO command. We receive the server ID and some
433 information about the server user requested. */
435 SILC_CLIENT_CMD_REPLY_FUNC(info)
437 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
438 SilcClient client = cmd->client;
439 SilcCommandStatus status;
442 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
443 SILC_GET16_MSB(status, tmp);
444 if (status != SILC_STATUS_OK) {
445 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
446 silc_client_command_reply_free(cmd);
451 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
455 /* XXX save server id */
457 /* Get server info */
458 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
462 silc_say(client, "Info: %s", tmp);
465 silc_client_command_reply_free(cmd);
468 SILC_CLIENT_CMD_REPLY_FUNC(away)
472 SILC_CLIENT_CMD_REPLY_FUNC(connect)
476 /* Received reply to PING command. The reply time is shown to user. */
478 SILC_CLIENT_CMD_REPLY_FUNC(ping)
480 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
481 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
482 SilcCommandStatus status;
486 time_t diff, curtime;
488 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
489 SILC_GET16_MSB(status, tmp);
490 if (status != SILC_STATUS_OK) {
491 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
495 curtime = time(NULL);
496 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
498 for (i = 0; i < win->ping_count; i++) {
499 if (!SILC_ID_SERVER_COMPARE(win->ping[i].dest_id, id)) {
500 diff = curtime - win->ping[i].start_time;
501 silc_say(cmd->client, "Ping reply from %s: %d second%s",
502 win->ping[i].dest_name, diff, diff == 1 ? "" : "s");
504 win->ping[i].start_time = 0;
505 silc_free(win->ping[i].dest_id);
506 win->ping[i].dest_id = NULL;
507 silc_free(win->ping[i].dest_name);
508 win->ping[i].dest_name = NULL;
514 silc_client_command_reply_free(cmd);
517 SILC_CLIENT_CMD_REPLY_FUNC(oper)
521 /* Received reply for JOIN command. */
523 SILC_CLIENT_CMD_REPLY_FUNC(join)
525 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
526 SilcClient client = cmd->client;
527 SilcCommandStatus status;
528 unsigned int argc, mode;
529 unsigned char *id_string;
530 char *topic, *tmp, *channel_name;
532 SILC_LOG_DEBUG(("Start"));
534 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
535 SILC_GET16_MSB(status, tmp);
536 if (status != SILC_STATUS_OK) {
537 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
541 argc = silc_command_get_arg_num(cmd->payload);
542 if (argc < 3 || argc > 4) {
543 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
547 /* Get channel name */
548 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
550 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
553 channel_name = strdup(tmp);
556 id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
558 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
562 /* Get channel mode */
563 tmp = silc_command_get_arg_type(cmd->payload, 4, NULL);
565 SILC_GET32_MSB(mode, tmp);
570 topic = silc_command_get_arg_type(cmd->payload, 5, NULL);
572 /* Save received Channel ID */
573 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
576 /* Print channel name on screen */
577 client->screen->bottom_line->channel = channel_name;
578 silc_screen_print_bottom_line(client->screen, 0);
581 silc_say(client, "Topic for %s: %s", channel_name, topic);
584 silc_client_command_reply_free(cmd);
587 SILC_CLIENT_CMD_REPLY_FUNC(motd)
591 SILC_CLIENT_CMD_REPLY_FUNC(umode)
595 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
599 SILC_CLIENT_CMD_REPLY_FUNC(kick)
603 SILC_CLIENT_CMD_REPLY_FUNC(restart)
607 SILC_CLIENT_CMD_REPLY_FUNC(close)
611 SILC_CLIENT_CMD_REPLY_FUNC(die)
615 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
619 /* Reply to LEAVE command. */
621 SILC_CLIENT_CMD_REPLY_FUNC(leave)
623 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
624 SilcCommandStatus status;
627 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
628 SILC_GET16_MSB(status, tmp);
629 if (status != SILC_STATUS_OK)
630 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
632 silc_client_command_reply_free(cmd);
635 /* Reply to NAMES command. Received list of client names on the channel
638 SILC_CLIENT_CMD_REPLY_FUNC(names)
640 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
641 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
642 SilcCommandStatus status;
643 SilcIDCacheEntry id_cache = NULL;
644 SilcChannelEntry channel;
645 SilcChannelID *channel_id = NULL;
646 SilcBuffer client_id_list;
649 int i, len1, len2, list_count = 0;
651 SILC_LOG_DEBUG(("Start"));
653 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
654 SILC_GET16_MSB(status, tmp);
655 if (status != SILC_STATUS_OK) {
656 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
661 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
663 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
666 channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
668 /* Get the name list of the channel */
669 name_list = silc_command_get_arg_type(cmd->payload, 3, &len1);
671 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
675 /* Get Client ID list */
676 tmp = silc_command_get_arg_type(cmd->payload, 4, &len2);
678 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
682 client_id_list = silc_buffer_alloc(len2);
683 silc_buffer_pull_tail(client_id_list, len2);
684 silc_buffer_put(client_id_list, tmp, len2);
686 /* Get the channel name */
687 if (!silc_idcache_find_by_id_one(win->channel_cache, (void *)channel_id,
688 SILC_ID_CHANNEL, &id_cache))
691 channel = (SilcChannelEntry)id_cache->context;
693 /* If there is pending command we know that user has called this command
694 and we will handle the name list differently. */
696 /* We will resolve all the necessary information about the people
697 on the channel. Only after that will we display the user list. */
698 for (i = 0; i < len1; i++) {
702 silc_client_command_pending_del(SILC_COMMAND_NAMES);
704 /* there is no pending callback it means that this command reply
705 has been received without calling the command, ie. server has sent
706 the reply without getting the command from us first. This happens
707 with SILC servers that sends NAMES reply after joining to a channel. */
709 /* Remove commas from list */
710 for (i = 0; i < len1; i++)
711 if (name_list[i] == ',') {
716 silc_say(cmd->client, "Users on %s: %s", channel->channel_name, name_list);
719 /* Cache the received name list and client ID's. This cache expires
720 whenever server sends notify message to channel. It means two things;
721 some user has joined or leaved the channel. */
722 for (i = 0; i < list_count; i++) {
723 int nick_len = strcspn(name_list, " ");
724 char *nickname = silc_calloc(nick_len, sizeof(*nickname));
725 SilcClientID *client_id;
726 SilcClientEntry client;
728 memcpy(nickname, name_list, nick_len);
729 client_id = silc_id_str2id(client_id_list->data, SILC_ID_CLIENT_LEN);
730 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
732 client = silc_calloc(1, sizeof(*client));
733 client->id = client_id;
734 client->nickname = nickname;
736 silc_idcache_add(win->client_cache, nickname, SILC_ID_CLIENT,
737 client_id, (void *)client, TRUE);
738 name_list = name_list + nick_len + 1;
741 silc_buffer_free(client_id_list);
745 silc_free(channel_id);
746 silc_client_command_reply_free(cmd);
749 /* Private message received. This processes the private message and
750 finally displays it on the screen. */
752 SILC_CLIENT_CMD_REPLY_FUNC(msg)
754 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
755 SilcClient client = cmd->client;
756 SilcBuffer buffer = (SilcBuffer)cmd->context;
757 unsigned short nick_len;
758 unsigned char *nickname, *message;
761 silc_buffer_unformat(buffer,
762 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
764 silc_buffer_pull(buffer, 2 + nick_len);
766 message = silc_calloc(buffer->len + 1, sizeof(char));
767 memcpy(message, buffer->data, buffer->len);
768 silc_print(client, "*%s* %s", nickname, message);
769 memset(message, 0, buffer->len);