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.6 2000/07/10 05:38:32 priikone
30 * Revision 1.5 2000/07/06 07:14:36 priikone
31 * Fixes to NAMES command handling.
32 * Fixes when leaving from channel.
34 * Revision 1.4 2000/07/05 06:12:34 priikone
35 * Tweaked NAMES command reply for better. Should now show users
36 * joined to a channel.
38 * Revision 1.3 2000/07/04 08:27:14 priikone
39 * Changes to LEAVE command -- more consistent now and does error
40 * handling better. Added INVITE, PING and part of NAMES commands.
41 * SilcPacketContext is included into command structure.
43 * Revision 1.2 2000/07/03 05:49:49 priikone
44 * Implemented LEAVE command. Minor bug fixes.
46 * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
47 * Imported from internal CVS/Added Log headers.
52 #include "clientincludes.h"
54 /* Client command reply list. */
55 SilcClientCommandReply silc_command_reply_list[] =
57 SILC_CLIENT_CMD_REPLY(whois, WHOIS),
58 SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
59 SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
60 SILC_CLIENT_CMD_REPLY(nick, NICK),
61 SILC_CLIENT_CMD_REPLY(list, LIST),
62 SILC_CLIENT_CMD_REPLY(topic, TOPIC),
63 SILC_CLIENT_CMD_REPLY(invite, INVITE),
64 SILC_CLIENT_CMD_REPLY(quit, QUIT),
65 SILC_CLIENT_CMD_REPLY(kill, KILL),
66 SILC_CLIENT_CMD_REPLY(info, INFO),
67 SILC_CLIENT_CMD_REPLY(away, AWAY),
68 SILC_CLIENT_CMD_REPLY(connect, CONNECT),
69 SILC_CLIENT_CMD_REPLY(ping, PING),
70 SILC_CLIENT_CMD_REPLY(oper, OPER),
71 SILC_CLIENT_CMD_REPLY(join, JOIN),
72 SILC_CLIENT_CMD_REPLY(motd, MOTD),
73 SILC_CLIENT_CMD_REPLY(umode, UMODE),
74 SILC_CLIENT_CMD_REPLY(cmode, CMODE),
75 SILC_CLIENT_CMD_REPLY(kick, KICK),
76 SILC_CLIENT_CMD_REPLY(restart, RESTART),
77 SILC_CLIENT_CMD_REPLY(close, CLOSE),
78 SILC_CLIENT_CMD_REPLY(die, DIE),
79 SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
80 SILC_CLIENT_CMD_REPLY(leave, LEAVE),
81 SILC_CLIENT_CMD_REPLY(names, NAMES),
86 /* Status message structure. Messages are defined below. */
88 SilcCommandStatus status;
90 } SilcCommandStatusMessage;
92 /* Status messages returned by the server */
93 #define STAT(x) SILC_STATUS_ERR_##x
94 const SilcCommandStatusMessage silc_command_status_messages[] = {
96 { STAT(NO_SUCH_NICK), "No such nickname" },
97 { STAT(NO_SUCH_CHANNEL), "No such channel" },
98 { STAT(NO_SUCH_SERVER), "No such server" },
99 { STAT(TOO_MANY_TARGETS), "Duplicate recipients. No message delivered" },
100 { STAT(NO_RECIPIENT), "No recipient given" },
101 { STAT(UNKNOWN_COMMAND), "Unknown command" },
102 { STAT(WILDCARDS), "Unknown command" },
103 { STAT(NO_CLIENT_ID), "No Client ID given" },
104 { STAT(NO_CHANNEL_ID), "No Channel ID given" },
105 { STAT(NO_SERVER_ID), "No Server ID given" },
106 { STAT(BAD_CLIENT_ID), "Bad Client ID" },
107 { STAT(BAD_CHANNEL_ID), "Bad Channel ID" },
108 { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
109 { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
110 { STAT(NICKNAME_IN_USE), "Nickname already exists" },
111 { STAT(NOT_ON_CHANNEL), "You are not on that channel" },
112 { STAT(USER_ON_CHANNEL), "User already on channel" },
113 { STAT(NOT_REGISTERED), "You have not registered" },
114 { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
115 { STAT(TOO_MANY_PARAMS), "Too many parameters" },
116 { STAT(PERM_DENIED), "Your host is not among the privileged" },
117 { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
118 { STAT(BAD_PASSWORD), "Cannot join channel. Incorrect password" },
119 { STAT(CHANNEL_IS_FULL), "Cannot join channel. Channel is full" },
120 { STAT(NOT_INVITED), "Cannot join channel. You have not been invited" },
121 { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
122 { STAT(UNKNOWN_MODE), "Unknown mode" },
123 { STAT(NOT_YOU), "Cannot change mode for other users" },
124 { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
125 { STAT(NO_SERVER_PRIV), "Permission denied. You are not server operator" },
126 { STAT(NO_ROUTER_PRIV), "Permission denied. You are not SILC operator" },
127 { STAT(BAD_NICKNAME), "Bad nickname" },
128 { STAT(BAD_CHANNEL), "Bad channel name" },
129 { STAT(AUTH_FAILED), "Authentication failed" },
134 /* Process received command reply. */
136 void silc_client_command_reply_process(SilcClient client,
137 SilcSocketConnection sock,
138 SilcPacketContext *packet)
140 SilcBuffer buffer = packet->buffer;
141 SilcClientCommandReplyContext ctx;
142 SilcCommandPayload payload;
144 /* Get command reply payload from packet */
145 payload = silc_command_parse_payload(buffer);
147 /* Silently ignore bad reply packet */
148 SILC_LOG_DEBUG(("Bad command reply packet"));
152 /* Allocate command reply context. This must be free'd by the
153 command reply routine receiving it. */
154 ctx = silc_calloc(1, sizeof(*ctx));
155 ctx->client = client;
157 ctx->payload = payload;
158 ctx->packet = packet;
160 /* Check for pending commands and mark to be exeucted */
161 SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
163 /* Execute command reply */
164 SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
167 /* Returns status message string */
170 silc_client_command_status_message(SilcCommandStatus status)
174 for (i = 0; silc_command_status_messages[i].message; i++) {
175 if (silc_command_status_messages[i].status == status)
179 if (silc_command_status_messages[i].message == NULL)
182 return silc_command_status_messages[i].message;
185 /* Free command reply context and its internals. */
187 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
190 silc_command_free_payload(cmd->payload);
195 /* Received reply for WHOIS command. This maybe called several times
196 for one WHOIS command as server may reply with list of results. */
198 SILC_CLIENT_CMD_REPLY_FUNC(whois)
200 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
201 SilcClient client = cmd->client;
202 SilcCommandStatus status;
205 SILC_LOG_DEBUG(("Start"));
207 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
208 SILC_GET16_MSB(status, tmp);
209 if (status != SILC_STATUS_OK) {
210 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
211 /* Take nickname which may be provided */
212 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
214 silc_say(cmd->client, "%s: %s", tmp,
215 silc_client_command_status_message(status));
217 silc_say(cmd->client, "%s",
218 silc_client_command_status_message(status));
221 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
226 /* Display one whois reply */
227 if (status == SILC_STATUS_OK) {
230 unsigned char *id_data;
231 char *nickname = NULL, *username = NULL;
232 char *realname = NULL;
235 memset(buf, 0, sizeof(buf));
237 argc = silc_command_get_arg_num(cmd->payload);
238 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
240 nickname = silc_command_get_arg_type(cmd->payload, 3, &len);
242 strncat(buf, nickname, len);
243 strncat(buf, " is ", 4);
246 username = silc_command_get_arg_type(cmd->payload, 4, &len);
248 strncat(buf, username, len);
251 realname = silc_command_get_arg_type(cmd->payload, 5, &len);
253 strncat(buf, " (", 2);
254 strncat(buf, realname, len);
255 strncat(buf, ")", 1);
259 /* Save received Client ID to ID cache */
260 /* XXX Maybe should not be saved as /MSG will get confused */
261 id = silc_id_str2id(id_data, SILC_ID_CLIENT);
262 client->current_win->client_id_cache_count[(int)nickname[0] - 32] =
263 silc_idcache_add(&client->current_win->
264 client_id_cache[(int)nickname[0] - 32],
265 client->current_win->
266 client_id_cache_count[(int)nickname[0] - 32],
267 strdup(nickname), SILC_ID_CLIENT, id, NULL);
270 silc_say(cmd->client, "%s", buf);
273 if (status == SILC_STATUS_LIST_START) {
277 if (status == SILC_STATUS_LIST_END) {
281 SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
284 silc_client_command_reply_free(cmd);
287 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
291 /* Received reply for IDENTIFY command. This maybe called several times
292 for one IDENTIFY command as server may reply with list of results.
293 This is totally silent and does not print anything on screen. */
295 SILC_CLIENT_CMD_REPLY_FUNC(identify)
297 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
298 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
299 SilcClientEntry client_entry;
300 SilcCommandStatus status;
303 SILC_LOG_DEBUG(("Start"));
305 #define CIDC(x) win->client_id_cache[(x) - 32]
306 #define CIDCC(x) win->client_id_cache_count[(x) - 32]
308 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
309 SILC_GET16_MSB(status, tmp);
310 if (status != SILC_STATUS_OK) {
311 if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
312 /* Take nickname which may be provided */
313 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
315 silc_say(cmd->client, "%s: %s", tmp,
316 silc_client_command_status_message(status));
318 silc_say(cmd->client, "%s",
319 silc_client_command_status_message(status));
322 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
327 /* Display one whois reply */
328 if (status == SILC_STATUS_OK) {
329 unsigned char *id_data;
332 id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
333 nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
335 /* Allocate client entry */
336 client_entry = silc_calloc(1, sizeof(*client_entry));
337 client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
338 client_entry->nickname = strdup(nickname);
340 /* Save received Client ID to ID cache */
342 silc_idcache_add(&CIDC(nickname[0]), CIDCC(nickname[0]),
343 client_entry->nickname, SILC_ID_CLIENT,
344 client_entry->id, client_entry);
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);
363 /* Received reply for command NICK. If everything went without errors
364 we just received our new Client ID. */
366 SILC_CLIENT_CMD_REPLY_FUNC(nick)
368 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
369 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
370 SilcCommandStatus status;
371 unsigned char *tmp, *id_string;
374 SILC_LOG_DEBUG(("Start"));
376 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
377 SILC_GET16_MSB(status, tmp);
378 if (status != SILC_STATUS_OK) {
379 silc_say(cmd->client, "Cannot set nickname: %s",
380 silc_client_command_status_message(status));
384 argc = silc_command_get_arg_num(cmd->payload);
385 if (argc < 2 || argc > 2) {
386 silc_say(cmd->client, "Cannot set nickname: bad reply to command");
390 /* Take received Client ID */
391 id_string = silc_command_get_arg_type(cmd->payload, 2, NULL);
392 silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
394 /* Update nickname on screen */
395 cmd->client->screen->bottom_line->nickname = win->nickname;
396 silc_screen_print_bottom_line(cmd->client->screen, 0);
399 silc_client_command_reply_free(cmd);
402 SILC_CLIENT_CMD_REPLY_FUNC(list)
406 SILC_CLIENT_CMD_REPLY_FUNC(topic)
410 /* Received reply to invite command. */
412 SILC_CLIENT_CMD_REPLY_FUNC(invite)
414 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
415 SilcCommandStatus status;
418 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
419 SILC_GET16_MSB(status, tmp);
420 if (status != SILC_STATUS_OK) {
421 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
422 silc_client_command_reply_free(cmd);
426 silc_client_command_reply_free(cmd);
429 SILC_CLIENT_CMD_REPLY_FUNC(quit)
433 SILC_CLIENT_CMD_REPLY_FUNC(kill)
437 /* Received reply to INFO command. We receive the server ID and some
438 information about the server user requested. */
440 SILC_CLIENT_CMD_REPLY_FUNC(info)
442 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
443 SilcClient client = cmd->client;
444 SilcCommandStatus status;
447 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
448 SILC_GET16_MSB(status, tmp);
449 if (status != SILC_STATUS_OK) {
450 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
451 silc_client_command_reply_free(cmd);
456 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
460 /* XXX save server id */
462 /* Get server info */
463 tmp = silc_command_get_arg_type(cmd->payload, 3, NULL);
467 silc_say(client, "Info: %s", tmp);
470 silc_client_command_reply_free(cmd);
473 SILC_CLIENT_CMD_REPLY_FUNC(away)
477 SILC_CLIENT_CMD_REPLY_FUNC(connect)
481 /* Received reply to PING command. The reply time is shown to user. */
483 SILC_CLIENT_CMD_REPLY_FUNC(ping)
485 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
486 SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
487 SilcCommandStatus status;
491 time_t diff, curtime;
493 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
494 SILC_GET16_MSB(status, tmp);
495 if (status != SILC_STATUS_OK) {
496 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
500 curtime = time(NULL);
501 id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
503 for (i = 0; i < win->ping_count; i++) {
504 if (!SILC_ID_SERVER_COMPARE(win->ping[i].dest_id, id)) {
505 diff = curtime - win->ping[i].start_time;
506 silc_say(cmd->client, "Ping reply from %s: %d second%s",
507 win->ping[i].dest_name, diff, diff == 1 ? "" : "s");
509 win->ping[i].start_time = 0;
510 silc_free(win->ping[i].dest_id);
511 win->ping[i].dest_id = NULL;
512 silc_free(win->ping[i].dest_name);
513 win->ping[i].dest_name = NULL;
519 silc_client_command_reply_free(cmd);
522 SILC_CLIENT_CMD_REPLY_FUNC(oper)
526 /* Received reply for JOIN command. */
528 SILC_CLIENT_CMD_REPLY_FUNC(join)
530 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
531 SilcClient client = cmd->client;
532 SilcCommandStatus status;
533 unsigned int argc, mode;
534 unsigned char *id_string;
535 char *topic, *tmp, *channel_name;
537 SILC_LOG_DEBUG(("Start"));
539 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
540 SILC_GET16_MSB(status, tmp);
541 if (status != SILC_STATUS_OK) {
542 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
546 argc = silc_command_get_arg_num(cmd->payload);
547 if (argc < 3 || argc > 4) {
548 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
552 /* Get channel name */
553 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
555 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
558 channel_name = strdup(tmp);
561 id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
563 silc_say(cmd->client, "Cannot join channel: Bad reply packet");
567 /* Get channel mode */
568 tmp = silc_command_get_arg_type(cmd->payload, 4, NULL);
570 SILC_GET32_MSB(mode, tmp);
575 topic = silc_command_get_arg_type(cmd->payload, 5, NULL);
577 /* Save received Channel ID */
578 silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
581 /* Print channel name on screen */
582 client->screen->bottom_line->channel = channel_name;
583 silc_screen_print_bottom_line(client->screen, 0);
586 silc_say(client, "Topic for %s: %s", channel_name, topic);
589 silc_client_command_reply_free(cmd);
592 SILC_CLIENT_CMD_REPLY_FUNC(motd)
596 SILC_CLIENT_CMD_REPLY_FUNC(umode)
600 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
604 SILC_CLIENT_CMD_REPLY_FUNC(kick)
608 SILC_CLIENT_CMD_REPLY_FUNC(restart)
612 SILC_CLIENT_CMD_REPLY_FUNC(close)
616 SILC_CLIENT_CMD_REPLY_FUNC(die)
620 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
624 /* Reply to LEAVE command. */
626 SILC_CLIENT_CMD_REPLY_FUNC(leave)
628 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
629 SilcClient client = cmd->client;
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 SilcIDCache *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 #define CIDC(x) win->channel_id_cache[(x)]
660 #define CIDCC(x) win->channel_id_cache_count[(x)]
661 #define CLC(x) win->client_id_cache[(x) - 32]
662 #define CLCC(x) win->client_id_cache_count[(x) - 32]
664 tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
665 SILC_GET16_MSB(status, tmp);
666 if (status != SILC_STATUS_OK) {
667 silc_say(cmd->client, "%s", silc_client_command_status_message(status));
672 tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
674 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
677 channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
679 /* Get the name list of the channel */
680 name_list = silc_command_get_arg_type(cmd->payload, 3, &len1);
682 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
686 /* Get Client ID list */
687 tmp = silc_command_get_arg_type(cmd->payload, 4, &len2);
689 silc_say(cmd->client, "Cannot get user list: Bad reply packet");
693 client_id_list = silc_buffer_alloc(len2);
694 silc_buffer_pull_tail(client_id_list, len2);
695 silc_buffer_put(client_id_list, tmp, len2);
697 /* Get the channel name */
698 for (i = 0; i < 96; i++) {
701 if (silc_idcache_find_by_id(CIDC(i), CIDCC(i), (void *)channel_id,
702 SILC_ID_CHANNEL, &id_cache))
708 channel = (SilcChannelEntry)id_cache->context;
710 /* If there is pending command we know that user has called this command
711 and we will handle the name list differently. */
713 /* We will resolve all the necessary information about the people
714 on the channel. Only after that will we display the user list. */
715 for (i = 0; i < len1; i++) {
719 silc_client_command_pending_del(SILC_COMMAND_NAMES);
721 /* there is no pending callback it means that this command reply
722 has been received without calling the command, ie. server has sent
723 the reply without getting the command from us first. This happens
724 with SILC servers that sends NAMES reply after joining to a channel. */
726 /* Remove commas from list */
727 for (i = 0; i < len1; i++)
728 if (name_list[i] == ',') {
733 silc_say(cmd->client, "Users on %s: %s", channel->channel_name, name_list);
736 /* Cache the received name list and client ID's. This cache expires
737 whenever server sends notify message to channel. It means two things;
738 some user has joined or leaved the channel. */
739 for (i = 0; i < list_count; i++) {
740 int nick_len = strcspn(name_list, " ");
741 char *nickname = silc_calloc(nick_len, sizeof(*nickname));
742 SilcClientID *client_id;
743 SilcClientEntry client;
745 memcpy(nickname, name_list, nick_len);
746 client_id = silc_id_str2id(client_id_list->data, SILC_ID_CLIENT_LEN);
747 silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
749 client = silc_calloc(1, sizeof(*client));
750 client->id = client_id;
751 client->nickname = nickname;
753 CLCC(nickname[0]) = silc_idcache_add(&CLC(nickname[0]), CLCC(nickname[0]),
754 nickname, SILC_ID_CLIENT,
755 client_id, (void *)client);
757 name_list = name_list + nick_len + 1;
760 silc_buffer_free(client_id_list);
764 silc_free(channel_id);
765 silc_client_command_reply_free(cmd);
772 /* Private message received. This processes the private message and
773 finally displays it on the screen. */
775 SILC_CLIENT_CMD_REPLY_FUNC(msg)
777 SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
778 SilcClient client = cmd->client;
779 SilcBuffer buffer = (SilcBuffer)cmd->context;
780 unsigned short nick_len;
781 unsigned char *nickname, *message;
782 SilcIDCache *id_cache;
783 unsigned char *id_string;
787 silc_buffer_unformat(buffer,
788 SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
790 silc_buffer_pull(buffer, 2 + nick_len);
793 /* Get ID of the sender */
794 id_string = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char *));
795 silc_buffer_push(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
796 memcpy(id_string, buffer->data, SILC_ID_CLIENT_LEN);
797 silc_buffer_pull(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
798 id = silc_id_str2id(id_string, SILC_ID_CLIENT);
799 silc_free(id_string);
801 /* Nickname should be verified if we don't have it in the cache */
802 if (silc_idcache_find_by_data(client->current_win->
803 client_id_cache[nickname[0] - 32],
804 client->current_win->
805 client_id_cache_count[nickname[0] - 32],
806 nickname, &id_cache) == FALSE) {
808 SilcClientCommandContext ctx;
811 /* Private message from unknown source, try to resolve it. */
818 message = silc_calloc(buffer->len + 1, sizeof(char));
819 memcpy(message, buffer->data, buffer->len);
820 silc_print(client, "*%s* %s", nickname, message);
821 memset(message, 0, buffer->len);