776b9b9de2ec4e9a677b0a8ece06ef35bba0c3c0
[silc.git] / apps / silc / command_reply.c
1 /*
2
3   command_reply.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
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.
13   
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.
18
19 */
20 /*
21  * Command reply functions are "the otherside" of the command functions.
22  * Reply to a command sent by server is handled by these functions.
23  */
24 /*
25  * $Id$
26  * $Log$
27  * Revision 1.4  2000/07/05 06:12:34  priikone
28  *      Tweaked NAMES command reply for better. Should now show users
29  *      joined to a channel.
30  *
31  * Revision 1.3  2000/07/04 08:27:14  priikone
32  *      Changes to LEAVE command -- more consistent now and does error
33  *      handling better. Added INVITE, PING and part of NAMES commands.
34  *      SilcPacketContext is included into command structure.
35  *
36  * Revision 1.2  2000/07/03 05:49:49  priikone
37  *      Implemented LEAVE command.  Minor bug fixes.
38  *
39  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
40  *      Imported from internal CVS/Added Log headers.
41  *
42  *
43  */
44
45 #include "clientincludes.h"
46
47 /* Client command reply list. */
48 SilcClientCommandReply silc_command_reply_list[] =
49 {
50   SILC_CLIENT_CMD_REPLY(whois, WHOIS),
51   SILC_CLIENT_CMD_REPLY(whowas, WHOWAS),
52   SILC_CLIENT_CMD_REPLY(identify, IDENTIFY),
53   SILC_CLIENT_CMD_REPLY(nick, NICK),
54   SILC_CLIENT_CMD_REPLY(list, LIST),
55   SILC_CLIENT_CMD_REPLY(topic, TOPIC),
56   SILC_CLIENT_CMD_REPLY(invite, INVITE),
57   SILC_CLIENT_CMD_REPLY(quit, QUIT),
58   SILC_CLIENT_CMD_REPLY(kill, KILL),
59   SILC_CLIENT_CMD_REPLY(info, INFO),
60   SILC_CLIENT_CMD_REPLY(away, AWAY),
61   SILC_CLIENT_CMD_REPLY(connect, CONNECT),
62   SILC_CLIENT_CMD_REPLY(ping, PING),
63   SILC_CLIENT_CMD_REPLY(oper, OPER),
64   SILC_CLIENT_CMD_REPLY(join, JOIN),
65   SILC_CLIENT_CMD_REPLY(motd, MOTD),
66   SILC_CLIENT_CMD_REPLY(umode, UMODE),
67   SILC_CLIENT_CMD_REPLY(cmode, CMODE),
68   SILC_CLIENT_CMD_REPLY(kick, KICK),
69   SILC_CLIENT_CMD_REPLY(restart, RESTART),
70   SILC_CLIENT_CMD_REPLY(close, CLOSE),
71   SILC_CLIENT_CMD_REPLY(die, DIE),
72   SILC_CLIENT_CMD_REPLY(silcoper, SILCOPER),
73   SILC_CLIENT_CMD_REPLY(leave, LEAVE),
74   SILC_CLIENT_CMD_REPLY(names, NAMES),
75
76   { NULL, 0 },
77 };
78
79 /* Status message structure. Messages are defined below. */
80 typedef struct {
81   SilcCommandStatus status;
82   char *message;
83 } SilcCommandStatusMessage;
84
85 /* Status messages returned by the server */
86 #define STAT(x) SILC_STATUS_ERR_##x
87 const SilcCommandStatusMessage silc_command_status_messages[] = {
88
89   { STAT(NO_SUCH_NICK),      "No such nickname" },
90   { STAT(NO_SUCH_CHANNEL),   "No such channel" },
91   { STAT(NO_SUCH_SERVER),    "No such server" },
92   { STAT(TOO_MANY_TARGETS),  "Duplicate recipients. No message delivered" },
93   { STAT(NO_RECIPIENT),      "No recipient given" },
94   { STAT(UNKNOWN_COMMAND),   "Unknown command" },
95   { STAT(WILDCARDS),         "Unknown command" },
96   { STAT(NO_CLIENT_ID),      "No Client ID given" },
97   { STAT(NO_CHANNEL_ID),     "No Channel ID given" },
98   { STAT(NO_SERVER_ID),      "No Server ID given" },
99   { STAT(BAD_CLIENT_ID),     "Bad Client ID" },
100   { STAT(BAD_CHANNEL_ID),    "Bad Channel ID" },
101   { STAT(NO_SUCH_CLIENT_ID), "No such Client ID" },
102   { STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
103   { STAT(NICKNAME_IN_USE),   "Nickname already exists" },
104   { STAT(NOT_ON_CHANNEL),    "You are not on that channel" },
105   { STAT(USER_ON_CHANNEL),   "User already on channel" },
106   { STAT(NOT_REGISTERED),    "You have not registered" },
107   { STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
108   { STAT(TOO_MANY_PARAMS),   "Too many parameters" },
109   { STAT(PERM_DENIED),       "Your host is not among the privileged" },
110   { STAT(BANNED_FROM_SERVER),"You are banned from this server" },
111   { STAT(BAD_PASSWORD),      "Cannot join channel. Incorrect password" },
112   { STAT(CHANNEL_IS_FULL),   "Cannot join channel. Channel is full" },
113   { STAT(NOT_INVITED),     "Cannot join channel. You have not been invited" },
114   { STAT(BANNED_FROM_CHANNEL), "Cannot join channel. You have been banned" },
115   { STAT(UNKNOWN_MODE),    "Unknown mode" },
116   { STAT(NOT_YOU),         "Cannot change mode for other users" },
117   { STAT(NO_CHANNEL_PRIV), "Permission denied. You are not channel operator" },
118   { STAT(NO_SERVER_PRIV),  "Permission denied. You are not server operator" },
119   { STAT(NO_ROUTER_PRIV),  "Permission denied. You are not SILC operator" },
120   { STAT(BAD_NICKNAME),    "Bad nickname" },
121   { STAT(BAD_CHANNEL),     "Bad channel name" },
122   { STAT(AUTH_FAILED),     "Authentication failed" },
123
124   { 0, NULL }
125 };
126
127 /* Process received command reply. */
128
129 void silc_client_command_reply_process(SilcClient client,
130                                        SilcSocketConnection sock,
131                                        SilcPacketContext *packet)
132 {
133   SilcBuffer buffer = packet->buffer;
134   SilcClientCommandReplyContext ctx;
135   SilcCommandPayload payload;
136
137   /* Get command reply payload from packet */
138   payload = silc_command_parse_payload(buffer);
139   if (!payload) {
140     /* Silently ignore bad reply packet */
141     SILC_LOG_DEBUG(("Bad command reply packet"));
142     return;
143   }
144   
145   /* Allocate command reply context. This must be free'd by the
146      command reply routine receiving it. */
147   ctx = silc_calloc(1, sizeof(*ctx));
148   ctx->client = client;
149   ctx->sock = sock;
150   ctx->payload = payload;
151   ctx->packet = packet;
152       
153   /* Check for pending commands and mark to be exeucted */
154   SILC_CLIENT_COMMAND_CHECK_PENDING(ctx);
155   
156   /* Execute command reply */
157   SILC_CLIENT_COMMAND_REPLY_EXEC(ctx);
158 }
159
160 /* Returns status message string */
161
162 static char *
163 silc_client_command_status_message(SilcCommandStatus status)
164 {
165   int i;
166
167   for (i = 0; silc_command_status_messages[i].message; i++) {
168     if (silc_command_status_messages[i].status == status)
169       break;
170   }
171
172   if (silc_command_status_messages[i].message == NULL)
173     return NULL;
174
175   return silc_command_status_messages[i].message;
176 }
177
178 /* Free command reply context and its internals. */
179
180 void silc_client_command_reply_free(SilcClientCommandReplyContext cmd)
181 {
182   if (cmd) {
183     silc_command_free_payload(cmd->payload);
184     silc_free(cmd);
185   }
186 }
187
188 /* Received reply for WHOIS command. This maybe called several times
189    for one WHOIS command as server may reply with list of results. */
190
191 SILC_CLIENT_CMD_REPLY_FUNC(whois)
192 {
193   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
194   SilcClient client = cmd->client;
195   SilcCommandStatus status;
196   unsigned char *tmp;
197
198   SILC_LOG_DEBUG(("Start"));
199
200   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
201   SILC_GET16_MSB(status, tmp);
202   if (status != SILC_STATUS_OK) {
203     if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
204       tmp += 2;
205       silc_say(cmd->client, "%s: %s", tmp,
206                silc_client_command_status_message(status));
207       goto out;
208     } else {
209       silc_say(cmd->client, "%s", silc_client_command_status_message(status));
210       goto out;
211     }
212   }
213
214   /* Display one whois reply */
215   if (status == SILC_STATUS_OK) {
216     char buf[256];
217     int argc, len;
218     unsigned char *id_data;
219     char *nickname = NULL, *username = NULL;
220     char *realname = NULL;
221     void *id;
222
223     memset(buf, 0, sizeof(buf));
224
225     argc = silc_command_get_arg_num(cmd->payload);
226     id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
227
228     nickname = silc_command_get_arg_type(cmd->payload, 3, &len);
229     if (nickname) {
230       strncat(buf, nickname, len);
231       strncat(buf, " is ", 4);
232     }
233
234     username = silc_command_get_arg_type(cmd->payload, 4, &len);
235     if (username) {
236       strncat(buf, username, len);
237     }
238
239     realname = silc_command_get_arg_type(cmd->payload, 5, &len);
240     if (realname) {
241       strncat(buf, " (", 2);
242       strncat(buf, realname, len);
243       strncat(buf, ")", 1);
244     }
245
246 #if 0
247     /* Save received Client ID to ID cache */
248     /* XXX Maybe should not be saved as /MSG will get confused */
249     id = silc_id_str2id(id_data, SILC_ID_CLIENT);
250     client->current_win->client_id_cache_count[(int)nickname[0] - 32] =
251     silc_idcache_add(&client->current_win->
252                      client_id_cache[(int)nickname[0] - 32],
253                      client->current_win->
254                      client_id_cache_count[(int)nickname[0] - 32],
255                      strdup(nickname), SILC_ID_CLIENT, id, NULL);
256 #endif
257
258     silc_say(cmd->client, "%s", buf);
259    }
260
261   if (status == SILC_STATUS_LIST_START) {
262
263   }
264
265   if (status == SILC_STATUS_LIST_END) {
266
267   }
268
269   SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
270
271  out:
272   silc_client_command_reply_free(cmd);
273 }
274
275 SILC_CLIENT_CMD_REPLY_FUNC(whowas)
276 {
277 }
278
279 /* Received reply for IDENTIFY command. This maybe called several times
280    for one IDENTIFY command as server may reply with list of results. 
281    This is totally silent and does not print anything on screen. */
282
283 SILC_CLIENT_CMD_REPLY_FUNC(identify)
284 {
285   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
286   SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
287   SilcClientEntry client_entry;
288   SilcCommandStatus status;
289   unsigned char *tmp;
290
291   SILC_LOG_DEBUG(("Start"));
292
293 #define CIDC(x) win->client_id_cache[(x) - 32]
294 #define CIDCC(x) win->client_id_cache_count[(x) - 32]
295
296   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
297   SILC_GET16_MSB(status, tmp);
298   if (status != SILC_STATUS_OK) {
299     if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
300       tmp += 2;
301       silc_say(cmd->client, "%s: %s", tmp,
302                silc_client_command_status_message(status));
303       goto out;
304     } else {
305       silc_say(cmd->client, "%s", silc_client_command_status_message(status));
306       goto out;
307     }
308   }
309
310   /* Display one whois reply */
311   if (status == SILC_STATUS_OK) {
312     unsigned char *id_data;
313     char *nickname;
314
315     id_data = silc_command_get_arg_type(cmd->payload, 2, NULL);
316     nickname = silc_command_get_arg_type(cmd->payload, 3, NULL);
317
318     /* Allocate client entry */
319     client_entry = silc_calloc(1, sizeof(*client_entry));
320     client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
321     client_entry->nickname = strdup(nickname);
322
323     /* Save received Client ID to ID cache */
324     CIDCC(nickname[0]) =
325       silc_idcache_add(&CIDC(nickname[0]), CIDCC(nickname[0]),
326                        client_entry->nickname, SILC_ID_CLIENT, 
327                        client_entry->id, client_entry);
328   }
329
330   if (status == SILC_STATUS_LIST_START) {
331
332   }
333
334   if (status == SILC_STATUS_LIST_END) {
335
336   }
337
338   SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_IDENTIFY);
339
340  out:
341   silc_client_command_reply_free(cmd);
342 #undef CIDC
343 #undef CIDCC
344 }
345
346 /* Received reply for command NICK. If everything went without errors
347    we just received our new Client ID. */
348
349 SILC_CLIENT_CMD_REPLY_FUNC(nick)
350 {
351   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
352   SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
353   SilcCommandStatus status;
354   unsigned char *tmp, *id_string;
355   int argc;
356
357   SILC_LOG_DEBUG(("Start"));
358
359   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
360   SILC_GET16_MSB(status, tmp);
361   if (status != SILC_STATUS_OK) {
362     silc_say(cmd->client, "Cannot set nickname: %s", 
363              silc_client_command_status_message(status));
364     goto out;
365   }
366
367   argc = silc_command_get_arg_num(cmd->payload);
368   if (argc < 2 || argc > 2) {
369     silc_say(cmd->client, "Cannot set nickname: bad reply to command");
370     goto out;
371   }
372
373   /* Take received Client ID */
374   id_string = silc_command_get_arg_type(cmd->payload, 2, NULL);
375   silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
376
377   /* Update nickname on screen */
378   cmd->client->screen->bottom_line->nickname = win->nickname;
379   silc_screen_print_bottom_line(cmd->client->screen, 0);
380
381  out:
382   silc_client_command_reply_free(cmd);
383 }
384
385 SILC_CLIENT_CMD_REPLY_FUNC(list)
386 {
387 }
388
389 SILC_CLIENT_CMD_REPLY_FUNC(topic)
390 {
391 }
392
393 /* Received reply to invite command. */
394
395 SILC_CLIENT_CMD_REPLY_FUNC(invite)
396 {
397   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
398   SilcCommandStatus status;
399   unsigned char *tmp;
400
401   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
402   SILC_GET16_MSB(status, tmp);
403   if (status != SILC_STATUS_OK) {
404     silc_say(cmd->client, "%s", silc_client_command_status_message(status));
405     silc_client_command_reply_free(cmd);
406     return;
407   }
408
409   silc_client_command_reply_free(cmd);
410 }
411  
412 SILC_CLIENT_CMD_REPLY_FUNC(quit)
413 {
414 }
415
416 SILC_CLIENT_CMD_REPLY_FUNC(kill)
417 {
418 }
419
420 SILC_CLIENT_CMD_REPLY_FUNC(info)
421 {
422 }
423
424 SILC_CLIENT_CMD_REPLY_FUNC(away)
425 {
426 }
427
428 SILC_CLIENT_CMD_REPLY_FUNC(connect)
429 {
430 }
431
432 /* Received reply to PING command. The reply time is shown to user. */
433
434 SILC_CLIENT_CMD_REPLY_FUNC(ping)
435 {
436   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
437   SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
438   SilcCommandStatus status;
439   void *id;
440   char *tmp;
441   int i;
442   time_t diff, curtime;
443
444   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
445   SILC_GET16_MSB(status, tmp);
446   if (status != SILC_STATUS_OK) {
447     silc_say(cmd->client, "%s", silc_client_command_status_message(status));
448     goto out;
449   }
450
451   curtime = time(NULL);
452   id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
453
454   for (i = 0; i < win->ping_count; i++) {
455     if (!SILC_ID_SERVER_COMPARE(win->ping[i].dest_id, id)) {
456       diff = curtime - win->ping[i].start_time;
457       silc_say(cmd->client, "Ping reply from %s: %d second%s", 
458                win->ping[i].dest_name, diff, diff == 1 ? "" : "s");
459
460       win->ping[i].start_time = 0;
461       silc_free(win->ping[i].dest_id);
462       win->ping[i].dest_id = NULL;
463       silc_free(win->ping[i].dest_name);
464       win->ping[i].dest_name = NULL;
465       goto out;
466     }
467   }
468
469  out:
470   silc_client_command_reply_free(cmd);
471 }
472
473 SILC_CLIENT_CMD_REPLY_FUNC(oper)
474 {
475 }
476
477 /* Received reply for JOIN command. */
478
479 SILC_CLIENT_CMD_REPLY_FUNC(join)
480 {
481   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
482   SilcClient client = cmd->client;
483   SilcCommandStatus status;
484   unsigned int argc, mode;
485   unsigned char *id_string;
486   char *topic, *tmp, *channel_name;
487
488   SILC_LOG_DEBUG(("Start"));
489
490   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
491   SILC_GET16_MSB(status, tmp);
492   if (status != SILC_STATUS_OK) {
493     silc_say(cmd->client, "%s", silc_client_command_status_message(status));
494     goto out;
495   }
496
497   argc = silc_command_get_arg_num(cmd->payload);
498   if (argc < 3 || argc > 4) {
499     silc_say(cmd->client, "Cannot join channel: Bad reply packet");
500     goto out;
501   }
502
503   /* Get channel name */
504   tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
505   channel_name = strdup(tmp);
506
507   /* Get Channel ID */
508   id_string = silc_command_get_arg_type(cmd->payload, 3, NULL);
509
510   /* Get channel mode */
511   tmp = silc_command_get_arg_type(cmd->payload, 4, NULL);
512   SILC_GET32_MSB(mode, tmp);
513
514   /* Get topic */
515   topic = silc_command_get_arg_type(cmd->payload, 5, NULL);
516
517   /* Save received Channel ID */
518   silc_client_new_channel_id(cmd->client, cmd->sock, channel_name, 
519                              mode, id_string);
520
521   /* Print channel name on screen */
522   client->screen->bottom_line->channel = channel_name;
523   silc_screen_print_bottom_line(client->screen, 0);
524
525   if (topic)
526     silc_say(client, "Topic for %s: %s", channel_name, topic);
527
528  out:
529   silc_client_command_reply_free(cmd);
530 }
531
532 SILC_CLIENT_CMD_REPLY_FUNC(motd)
533 {
534 }
535
536 SILC_CLIENT_CMD_REPLY_FUNC(umode)
537 {
538 }
539
540 SILC_CLIENT_CMD_REPLY_FUNC(cmode)
541 {
542 }
543
544 SILC_CLIENT_CMD_REPLY_FUNC(kick)
545 {
546 }
547
548 SILC_CLIENT_CMD_REPLY_FUNC(restart)
549 {
550 }
551  
552 SILC_CLIENT_CMD_REPLY_FUNC(close)
553 {
554 }
555  
556 SILC_CLIENT_CMD_REPLY_FUNC(die)
557 {
558 }
559  
560 SILC_CLIENT_CMD_REPLY_FUNC(silcoper)
561 {
562 }
563
564 /* Reply to LEAVE command. */
565
566 SILC_CLIENT_CMD_REPLY_FUNC(leave)
567 {
568   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
569   SilcClient client = cmd->client;
570   SilcCommandStatus status;
571   unsigned char *tmp;
572
573   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
574   SILC_GET16_MSB(status, tmp);
575   if (status != SILC_STATUS_OK)
576     silc_say(cmd->client, "%s", silc_client_command_status_message(status));
577
578   silc_client_command_reply_free(cmd);
579 }
580
581 /* Reply to NAMES command. Received list of client names on the channel 
582    we requested. */
583
584 SILC_CLIENT_CMD_REPLY_FUNC(names)
585 {
586   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
587   SilcClientWindow win = (SilcClientWindow)cmd->sock->user_data;
588   SilcCommandStatus status;
589   SilcIDCache *id_cache = NULL;
590   SilcChannelEntry channel;
591   SilcChannelID *channel_id = NULL;
592   unsigned char *tmp;
593   char *name_list;
594   int i, len;
595
596   SILC_LOG_DEBUG(("Start"));
597
598 #define CIDC(x) win->channel_id_cache[(x)]
599 #define CIDCC(x) win->channel_id_cache_count[(x)]
600
601   tmp = silc_command_get_arg_type(cmd->payload, 1, NULL);
602   SILC_GET16_MSB(status, tmp);
603   if (status != SILC_STATUS_OK) {
604     silc_say(cmd->client, "%s", silc_client_command_status_message(status));
605     goto out;
606   }
607
608   /* Get channel ID */
609   tmp = silc_command_get_arg_type(cmd->payload, 2, NULL);
610   if (!tmp)
611     goto out;
612   channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
613
614   /* Get the name list of the channel */
615   name_list = silc_command_get_arg_type(cmd->payload, 3, &len);
616   if (!name_list)
617     goto out;
618
619   /* Get the channel name */
620   for (i = 0; i < 96; i++) {
621     if (CIDC(i) == NULL)
622       continue;
623     if (silc_idcache_find_by_id(CIDC(i), CIDCC(i), (void *)channel_id, 
624                                 SILC_ID_CHANNEL, &id_cache))
625       break;
626   }
627   if (!id_cache)
628     goto out;
629   
630   channel = (SilcChannelEntry)id_cache->context;
631
632   /* If there are pending commands set for this command reply we will
633      execute them and let them handle the received name list. */
634   if (cmd->callback) {
635     SILC_CLIENT_COMMAND_EXEC_PENDING(cmd, SILC_COMMAND_WHOIS);
636   } else {
637     /* there is no pending callback it means that this command reply
638        has been received without calling the command, ie. server has sent
639        the reply without getting the command from us first. This happens
640        with SILC servers that sends NAMES reply after joining to a channel. */
641
642     /* Remove commas from list */
643     for (i = 0; i < len; i++)
644       if (name_list[i] == ',')
645         name_list[i] = ' ';
646
647     silc_say(cmd->client, "Users on %s: %s", channel->channel_name, name_list);
648   }
649
650  out:
651   if (channel_id)
652     silc_free(channel_id);
653   silc_client_command_reply_free(cmd);
654 #undef CIDC
655 #undef CIDCC
656 }
657
658 /* Private message received. This processes the private message and
659    finally displays it on the screen. */
660
661 SILC_CLIENT_CMD_REPLY_FUNC(msg)
662 {
663   SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
664   SilcClient client = cmd->client;
665   SilcBuffer buffer = (SilcBuffer)cmd->context;
666   unsigned short nick_len;
667   unsigned char *nickname, *message;
668   SilcIDCache *id_cache;
669   unsigned char *id_string;
670   void *id;
671
672   /* Get nickname */
673   silc_buffer_unformat(buffer, 
674                        SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len),
675                        SILC_STR_END);
676   silc_buffer_pull(buffer, 2 + nick_len);
677
678 #if 0
679   /* Get ID of the sender */
680   id_string = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char *));
681   silc_buffer_push(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
682   memcpy(id_string, buffer->data, SILC_ID_CLIENT_LEN);
683   silc_buffer_pull(buffer, SILC_ID_CLIENT_LEN + SILC_ID_CLIENT_LEN);
684   id = silc_id_str2id(id_string, SILC_ID_CLIENT);
685   silc_free(id_string);
686
687   /* Nickname should be verified if we don't have it in the cache */
688   if (silc_idcache_find_by_data(client->current_win->
689                                 client_id_cache[nickname[0] - 32],
690                                 client->current_win->
691                                 client_id_cache_count[nickname[0] - 32],
692                                 nickname, &id_cache) == FALSE) {
693
694     SilcClientCommandContext ctx;
695     char whois[255];
696
697     /* Private message from unknown source, try to resolve it. */
698
699
700     return;
701   }
702 #endif
703      
704   message = silc_calloc(buffer->len + 1, sizeof(char));
705   memcpy(message, buffer->data, buffer->len);
706   silc_print(client, "*%s* %s", nickname, message);
707   memset(message, 0, buffer->len);
708   silc_free(message);
709 }