Added Requested Attributes sending and receiving support to
[silc.git] / lib / silcclient / client_notify.c
1 /*
2
3   client_notify.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1997 - 2002 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; version 2 of the License.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18 */
19 /* $Id$ */
20 /* This file includes the Notify packet handling. Notify packets are
21    important packets sent by the server. They tell different things to the
22    client such as nick changes, mode changes etc. */
23
24 #include "silcincludes.h"
25 #include "silcclient.h"
26 #include "client_internal.h"
27
28 /* Context used for resolving client, channel and server info. */
29 typedef struct {
30   void *packet;
31   void *context;
32   SilcSocketConnection sock;
33 } *SilcClientNotifyResolve;
34
35 SILC_TASK_CALLBACK(silc_client_notify_check_client)
36
37   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
38   SilcClient client = res->context;
39   SilcClientConnection conn = res->sock->user_data;
40   SilcClientID *client_id = res->packet;
41   silc_client_get_client_by_id_resolve(client, conn, client_id,
42                                        NULL, NULL, NULL);
43   silc_free(client_id);
44   silc_socket_free(res->sock);
45   silc_free(res);
46 }
47
48 SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
49 {
50   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
51   SilcClient client = res->context;
52   SilcClientConnection conn = res->sock->user_data;
53   SilcClientID *client_id = res->packet;
54   SilcClientEntry client_entry;
55   client_entry = silc_client_get_client_by_id(client, conn, client_id);
56   if (client_entry)
57     silc_client_del_client(client, conn, client_entry);
58   silc_free(client_id);
59   silc_socket_free(res->sock);
60   silc_free(res);
61 }
62
63 /* Called when notify is received and some async operation (such as command)
64    is required before processing the notify message. This calls again the
65    silc_client_notify_by_server and reprocesses the original notify packet. */
66
67 static void silc_client_notify_by_server_pending(void *context, void *context2)
68 {
69   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
70   SilcClientCommandReplyContext reply = 
71     (SilcClientCommandReplyContext)context2;
72
73   SILC_LOG_DEBUG(("Start"));
74
75   if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
76     goto out;
77
78   silc_client_notify_by_server(res->context, res->sock, res->packet);
79
80  out:
81   silc_socket_free(res->sock);
82   silc_packet_context_free(res->packet);
83   silc_free(res);
84 }
85
86 /* Resets the channel entry's resolve_cmd_ident after whatever-thing
87    was resolved is completed. */
88
89 static void silc_client_channel_cond(void *context, void *context2)
90 {
91   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
92   SilcClient client = res->context;
93   SilcClientConnection conn = res->sock->user_data;
94   SilcChannelID *channel_id = res->packet;
95   SilcChannelEntry channel;
96   channel = silc_client_get_channel_by_id(client, conn, channel_id);
97   if (channel)
98     channel->resolve_cmd_ident = 0;
99   silc_free(channel_id);
100   silc_socket_free(res->sock);
101   silc_free(res);
102 }
103
104 /* Function that starts waiting for the `cmd_ident' to arrive and
105    marks the channel info being resolved.  */
106
107 static void silc_client_channel_set_wait(SilcClient client,
108                                          SilcClientConnection conn,
109                                          SilcChannelEntry channel,
110                                          SilcUInt16 cmd_ident)
111 {
112   SilcClientNotifyResolve res;
113
114   if (!channel->resolve_cmd_ident) {
115     res = silc_calloc(1, sizeof(*res));
116     res->context = client;
117     res->sock = silc_socket_dup(conn->sock);
118     res->packet = silc_id_dup(channel->id, SILC_ID_CHANNEL);
119     silc_client_command_pending(conn, SILC_COMMAND_NONE, cmd_ident,
120                                 silc_client_channel_cond, res);
121     channel->resolve_cmd_ident = cmd_ident;
122   }
123 }
124
125 /* Attaches to the channel's resolving cmd ident and calls the 
126    notify handling with `packet' after it's received. */
127
128 static void silc_client_channel_wait(SilcClient client,
129                                      SilcClientConnection conn,
130                                      SilcChannelEntry channel,
131                                      SilcPacketContext *packet)
132 {
133   SilcClientNotifyResolve res;
134
135   if (!channel->resolve_cmd_ident)
136     return;
137
138   res = silc_calloc(1, sizeof(*res));
139   res->packet = silc_packet_context_dup(packet);
140   res->context = client;
141   res->sock = silc_socket_dup(conn->sock);
142
143   silc_client_command_pending(conn, SILC_COMMAND_NONE,
144                               channel->resolve_cmd_ident,
145                               silc_client_notify_by_server_pending, res);
146 }
147
148 /* Resolve client, channel or server information. */
149
150 static void silc_client_notify_by_server_resolve(SilcClient client,
151                                                  SilcClientConnection conn,
152                                                  SilcPacketContext *packet,
153                                                  SilcIdType id_type,
154                                                  void *id)
155 {
156   SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
157   SilcBuffer idp = silc_id_payload_encode(id, id_type);
158
159   res->packet = silc_packet_context_dup(packet);
160   res->context = client;
161   res->sock = silc_socket_dup(conn->sock);
162
163   /* For client resolving use WHOIS, and otherwise use IDENTIFY */
164   if (id_type == SILC_ID_CLIENT) {
165     silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
166                                  silc_client_command_reply_whois_i, 0,
167                                  ++conn->cmd_ident);
168     silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
169                              1, 4, idp->data, idp->len);
170     silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
171                                 silc_client_notify_by_server_pending, res);
172   } else {
173     silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
174                                  silc_client_command_reply_identify_i, 0,
175                                  ++conn->cmd_ident);
176     silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY, 
177                              conn->cmd_ident, 1, 5, idp->data, idp->len);
178     silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
179                                 silc_client_notify_by_server_pending, res);
180   }
181   silc_buffer_free(idp);
182 }
183
184 /* Received notify message from server */
185
186 void silc_client_notify_by_server(SilcClient client,
187                                   SilcSocketConnection sock,
188                                   SilcPacketContext *packet)
189 {
190   SilcBuffer buffer = packet->buffer;
191   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
192   SilcNotifyPayload payload;
193   SilcNotifyType type;
194   SilcArgumentPayload args;
195
196   void *id;
197   SilcIdType id_type;
198   SilcClientID *client_id = NULL;
199   SilcChannelID *channel_id = NULL;
200   SilcServerID *server_id = NULL;
201   SilcClientEntry client_entry = NULL;
202   SilcClientEntry client_entry2 = NULL;
203   SilcChannelEntry channel;
204   SilcChannelUser chu;
205   SilcServerEntry server;
206   unsigned char *tmp;
207   SilcUInt32 tmp_len, mode;
208
209   SILC_LOG_DEBUG(("Start"));
210
211   payload = silc_notify_payload_parse(buffer->data, buffer->len);
212   if (!payload)
213     goto out;
214
215   type = silc_notify_get_type(payload);
216   args = silc_notify_get_args(payload);
217   if (!args)
218     goto out;
219
220   switch(type) {
221   case SILC_NOTIFY_TYPE_NONE:
222     /* Notify application */
223     client->internal->ops->notify(client, conn, type, 
224                                   silc_argument_get_arg_type(args, 1, NULL));
225     break;
226
227   case SILC_NOTIFY_TYPE_INVITE:
228     /* 
229      * Someone invited me to a channel. Find Client and Channel entries
230      * for the application.
231      */
232     
233     SILC_LOG_DEBUG(("Notify: INVITE"));
234
235     /* Get Channel ID */
236     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
237     if (!tmp)
238       goto out;
239
240     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
241     if (!channel_id)
242       goto out;
243
244     /* Get the channel entry */
245     channel = silc_client_get_channel_by_id(client, conn, channel_id);
246
247     /* Get sender Client ID */
248     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
249     if (!tmp)
250       goto out;
251
252     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
253     if (!client_id)
254       goto out;
255
256     /* Find Client entry and if not found query it */
257     client_entry = silc_client_get_client_by_id(client, conn, client_id);
258     if (!client_entry) {
259       silc_client_notify_by_server_resolve(client, conn, packet, 
260                                            SILC_ID_CLIENT, client_id);
261       goto out;
262     }
263
264     /* Get the channel name */
265     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
266     if (!tmp)
267       goto out;
268
269     /* Notify application */
270     client->internal->ops->notify(client, conn, type, channel, tmp, 
271                                   client_entry);
272     break;
273
274   case SILC_NOTIFY_TYPE_JOIN:
275     /*
276      * Someone has joined to a channel. Get their ID and nickname and
277      * cache them for later use.
278      */
279
280     SILC_LOG_DEBUG(("Notify: JOIN"));
281
282     /* Get Client ID */
283     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
284     if (!tmp)
285       goto out;
286
287     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
288     if (!client_id)
289       goto out;
290
291     /* Find Client entry and if not found query it */
292     client_entry = silc_client_get_client_by_id(client, conn, client_id);
293     if (!client_entry) {
294       silc_client_notify_by_server_resolve(client, conn, packet, 
295                                            SILC_ID_CLIENT, client_id);
296       goto out;
297     }
298
299     /* If nickname or username hasn't been resolved, do so */
300     if (!client_entry->nickname || !client_entry->username) {
301       if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
302         client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
303         goto out;
304       }
305       silc_client_notify_by_server_resolve(client, conn, packet, 
306                                            SILC_ID_CLIENT, client_id);
307       client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
308       client_entry->resolve_cmd_ident = conn->cmd_ident;
309       goto out;
310     } else {
311       if (client_entry != conn->local_entry)
312         silc_client_nickname_format(client, conn, client_entry);
313     }
314
315     /* Get Channel ID */
316     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
317     if (!tmp)
318       goto out;
319
320     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
321     if (!channel_id)
322       goto out;
323
324     /* Get channel entry */
325     channel = silc_client_get_channel_by_id(client, conn, channel_id);
326     if (!channel)
327       break;
328
329     /* Join the client to channel */
330     if (!silc_client_on_channel(channel, client_entry)) {
331       chu = silc_calloc(1, sizeof(*chu));
332       chu->client = client_entry;
333       chu->channel = channel;
334       silc_hash_table_add(channel->user_list, client_entry, chu);
335       silc_hash_table_add(client_entry->channels, channel, chu);
336     }
337
338     /* Notify application. The channel entry is sent last as this notify
339        is for channel but application don't know it from the arguments
340        sent by server. */
341     client->internal->ops->notify(client, conn, type, client_entry, channel);
342     break;
343
344   case SILC_NOTIFY_TYPE_LEAVE:
345     /*
346      * Someone has left a channel. We will remove it from the channel but
347      * we'll keep it in the cache in case we'll need it later.
348      */
349     
350     SILC_LOG_DEBUG(("Notify: LEAVE"));
351
352     /* Get Client ID */
353     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
354     if (!tmp)
355       goto out;
356
357     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
358     if (!client_id)
359       goto out;
360
361     /* Find Client entry */
362     client_entry = 
363       silc_client_get_client_by_id(client, conn, client_id);
364     if (!client_entry)
365       goto out;
366
367     /* Get channel entry */
368     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
369                                 SILC_ID_CHANNEL);
370     if (!channel_id)
371       goto out;
372     channel = silc_client_get_channel_by_id(client, conn, channel_id);
373     if (!channel)
374       break;
375
376     /* Remove client from channel */
377     chu = silc_client_on_channel(channel, client_entry);
378     if (chu) {
379       silc_hash_table_del(client_entry->channels, channel);
380       silc_hash_table_del(channel->user_list, client_entry);
381       silc_free(chu);
382     }
383
384     /* Some client implementations actually quit network by first doing
385        LEAVE and then immediately SIGNOFF.  We'll check for this by doing 
386        check for the client after 5 - 34 seconds.  If it is not valid after
387        that we'll remove the client from cache. */
388     if (!silc_hash_table_count(client_entry->channels)) {
389       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
390       res->context = client;
391       res->sock = silc_socket_dup(conn->sock);
392       res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
393       silc_schedule_task_add(client->schedule, conn->sock->sock,
394                              silc_client_notify_check_client, res,
395                              (5 + (silc_rng_get_rn16(client->rng) % 29)),
396                              0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
397     }
398
399     /* Notify application. The channel entry is sent last as this notify
400        is for channel but application don't know it from the arguments
401        sent by server. */
402     client->internal->ops->notify(client, conn, type, client_entry, channel);
403     break;
404
405   case SILC_NOTIFY_TYPE_SIGNOFF:
406     /*
407      * Someone left SILC. We'll remove it from all channels and from cache.
408      */
409
410     SILC_LOG_DEBUG(("Notify: SIGNOFF"));
411
412     /* Get Client ID */
413     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
414     if (!tmp)
415       goto out;
416
417     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
418     if (!client_id)
419       goto out;
420
421     /* Find Client entry */
422     client_entry = 
423       silc_client_get_client_by_id(client, conn, client_id);
424     if (!client_entry)
425       goto out;
426
427     /* Remove from all channels */
428     silc_client_remove_from_channels(client, conn, client_entry);
429
430     /* Remove from cache */
431     silc_idcache_del_by_context(conn->client_cache, client_entry);
432
433     /* Get signoff message */
434     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
435     if (tmp_len > 128)
436       tmp = NULL;
437
438     /* Notify application */
439     client->internal->ops->notify(client, conn, type, client_entry, tmp);
440
441     /* Free data */
442     silc_client_del_client_entry(client, conn, client_entry);
443     break;
444
445   case SILC_NOTIFY_TYPE_TOPIC_SET:
446     /*
447      * Someone set the topic on a channel.
448      */
449
450     SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
451
452     /* Get channel entry */
453     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
454                                 SILC_ID_CHANNEL);
455     if (!channel_id)
456       goto out;
457     channel = silc_client_get_channel_by_id(client, conn, channel_id);
458     if (!channel)
459       break;
460
461     /* Get ID */
462     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
463     if (!tmp)
464       goto out;
465     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
466     if (!id)
467       goto out;
468
469     /* Find Client entry */
470     if (id_type == SILC_ID_CLIENT) {
471       /* Find Client entry */
472       client_id = id;
473       client_entry = silc_client_get_client_by_id(client, conn, client_id);
474       if (!client_entry) {
475         silc_client_channel_set_wait(client, conn, channel,
476                                      conn->cmd_ident + 1);
477         silc_client_notify_by_server_resolve(client, conn, packet, 
478                                              SILC_ID_CLIENT, client_id);
479         goto out;
480       }
481     } else if (id_type == SILC_ID_SERVER) {
482       /* Find Server entry */
483       server_id = id;
484       server = silc_client_get_server_by_id(client, conn, server_id);
485       if (!server) {
486         silc_client_channel_set_wait(client, conn, channel,
487                                      conn->cmd_ident + 1);
488         silc_client_notify_by_server_resolve(client, conn, packet, 
489                                              SILC_ID_SERVER, server_id);
490         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
491         if (!server)
492           goto out;
493
494         server->resolve_cmd_ident = conn->cmd_ident;
495         server_id = NULL;
496         goto out;
497       }
498
499       /* If entry being resoled, wait for it before processing this notify */
500       if (server->resolve_cmd_ident) {
501         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
502         res->packet = silc_packet_context_dup(packet);
503         res->context = client;
504         res->sock = silc_socket_dup(conn->sock);
505         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
506                                     server->resolve_cmd_ident,
507                                     silc_client_notify_by_server_pending, res);
508         goto out;
509       }
510       
511       /* Save the pointer to the client_entry pointer */
512       client_entry = (SilcClientEntry)server;
513     } else {
514       /* Find Channel entry */
515       silc_free(channel_id);
516       channel_id = id;
517       client_entry = (SilcClientEntry)
518         silc_client_get_channel_by_id(client, conn, channel_id);
519       if (!client_entry) {
520         silc_client_channel_set_wait(client, conn, channel,
521                                      conn->cmd_ident + 1);
522         silc_client_notify_by_server_resolve(client, conn, packet, 
523                                              SILC_ID_CHANNEL, channel_id);
524         goto out;
525       }
526     }
527
528     /* Get topic */
529     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
530     if (!tmp)
531       goto out;
532
533     /* If information is being resolved for this channel, wait for it */
534     if (channel->resolve_cmd_ident) {
535       silc_client_channel_wait(client, conn, channel, packet);
536       goto out;
537     }
538
539     /* Notify application. The channel entry is sent last as this notify
540        is for channel but application don't know it from the arguments
541        sent by server. */
542     client->internal->ops->notify(client, conn, type, id_type,
543                                   client_entry, tmp, channel);
544
545     break;
546
547   case SILC_NOTIFY_TYPE_NICK_CHANGE:
548     /*
549      * Someone changed their nickname. If we don't have entry for the new
550      * ID we will query it and return here after it's done. After we've
551      * returned we fetch the old entry and free it and notify the 
552      * application.
553      */
554
555     SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
556
557     /* Get old Client ID */
558     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
559     if (!tmp)
560       goto out;
561
562     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
563     if (!client_id)
564       goto out;
565
566     /* Ignore my ID */
567     if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
568       break;
569
570     /* Find old Client entry */
571     client_entry = silc_client_get_client_by_id(client, conn, client_id);
572     if (!client_entry)
573       goto out;
574     silc_free(client_id);
575
576     /* Wait for resolving if necessary */
577     if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
578       SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
579       res->packet = silc_packet_context_dup(packet);
580       res->context = client;
581       res->sock = silc_socket_dup(conn->sock);
582       silc_client_command_pending(conn, SILC_COMMAND_NONE, 
583                                   client_entry->resolve_cmd_ident,
584                                   silc_client_notify_by_server_pending, res);
585       goto out;
586     }
587
588     client_entry->valid = FALSE;
589
590     /* Get new Client ID */
591     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
592     if (!tmp)
593       goto out;
594
595     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
596     if (!client_id)
597       goto out;
598
599     /* From protocol version 1.1 we get the new nickname in notify as well,
600        so we don't have to resolve it.  Do it the hard way if server doesn't
601        send it to us. */
602     tmp = silc_argument_get_arg_type(args, 3, NULL);
603     if (tmp) {
604       /* Protocol version 1.1 */
605       char *tmp_nick = NULL;
606
607       /* Check whether nickname changed at all.  It is possible that nick
608          change notify is received but nickname didn't changed, only the
609          ID changes. */
610       if (client->internal->params->nickname_parse)
611         client->internal->params->nickname_parse(client_entry->nickname,
612                                                  &tmp_nick);
613       else
614         tmp_nick = strdup(tmp);
615
616       if (tmp_nick && !strcmp(tmp, tmp_nick)) {
617         /* Nickname didn't change. Update only the ID */
618         silc_idcache_del_by_context(conn->client_cache, client_entry);
619         silc_free(client_entry->id);
620         client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
621         silc_idcache_add(conn->client_cache, strdup(tmp),
622                          client_entry->id, client_entry, 0, NULL);
623
624         /* Notify application */
625         client->internal->ops->notify(client, conn, type, 
626                                       client_entry, client_entry);
627         break;
628       }
629       silc_free(tmp_nick);
630
631       /* Create new client entry, and save all old information with the
632          new nickname and client ID */
633       client_entry2 = silc_client_add_client(client, conn, NULL, NULL, 
634                                              client_entry->realname,
635                                              silc_id_dup(client_id, 
636                                                          SILC_ID_CLIENT), 0);
637       if (!client_entry2)
638         goto out;
639
640       if (client_entry->server)
641         client_entry2->server = strdup(client_entry->server);
642       if (client_entry->username)
643         client_entry2->username = strdup(client_entry->username);
644       if (client_entry->hostname)
645         client_entry2->hostname = strdup(client_entry->hostname);
646       silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
647                                 client_entry->mode);
648     } else {
649       /* Protocol version 1.0 */
650
651       /* Find client entry and if not found resolve it */
652       client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
653       if (!client_entry2) {
654         /* Resolve the entry information */
655         silc_client_notify_by_server_resolve(client, conn, packet, 
656                                              SILC_ID_CLIENT, client_id);
657
658         /* Add the new entry even though we resolved it. This is because we
659            want to replace the old entry with the new entry here right now. */
660         client_entry2 = 
661           silc_client_add_client(client, conn, NULL, NULL, NULL, 
662                                  silc_id_dup(client_id, SILC_ID_CLIENT), 
663                                  client_entry->mode);
664
665         /* Replace old ID entry with new one on all channels. */
666         silc_client_replace_from_channels(client, conn, client_entry,
667                                           client_entry2);
668         break;
669       }
670
671       if (client_entry2 != conn->local_entry)
672         silc_client_nickname_format(client, conn, client_entry2);
673     }
674
675     /* Remove the old from cache */
676     silc_idcache_del_by_context(conn->client_cache, client_entry);
677     
678     /* Replace old ID entry with new one on all channels. */
679     silc_client_replace_from_channels(client, conn, client_entry,
680                                       client_entry2);
681
682     /* Notify application */
683     client->internal->ops->notify(client, conn, type, 
684                                   client_entry, client_entry2);
685     
686     /* Free old client entry */
687     silc_client_del_client_entry(client, conn, client_entry);
688
689     break;
690
691   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
692     /*
693      * Someone changed a channel mode
694      */
695
696     SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
697
698     /* Get channel entry */
699     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
700                                 SILC_ID_CHANNEL);
701     if (!channel_id)
702       goto out;
703     channel = silc_client_get_channel_by_id(client, conn, channel_id);
704     if (!channel)
705       goto out;
706
707     /* Get ID */
708     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
709     if (!tmp)
710       goto out;
711     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
712     if (!id)
713       goto out;
714
715     /* Find Client entry */
716     if (id_type == SILC_ID_CLIENT) {
717       /* Find Client entry */
718       client_id = id;
719       client_entry = silc_client_get_client_by_id(client, conn, client_id);
720       if (!client_entry) {
721         silc_client_channel_set_wait(client, conn, channel,
722                                      conn->cmd_ident + 1);
723         silc_client_notify_by_server_resolve(client, conn, packet, 
724                                              SILC_ID_CLIENT, client_id);
725         goto out;
726       }
727     } else if (id_type == SILC_ID_SERVER) {
728       /* Find Server entry */
729       server_id = id;
730       server = silc_client_get_server_by_id(client, conn, server_id);
731       if (!server) {
732         silc_client_channel_set_wait(client, conn, channel,
733                                      conn->cmd_ident + 1);
734         silc_client_notify_by_server_resolve(client, conn, packet, 
735                                              SILC_ID_SERVER, server_id);
736         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
737         if (!server)
738           goto out;
739
740         server->resolve_cmd_ident = conn->cmd_ident;
741         server_id = NULL;
742         goto out;
743       }
744
745       /* If entry being resoled, wait for it before processing this notify */
746       if (server->resolve_cmd_ident) {
747         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
748         res->packet = silc_packet_context_dup(packet);
749         res->context = client;
750         res->sock = silc_socket_dup(conn->sock);
751         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
752                                     server->resolve_cmd_ident,
753                                     silc_client_notify_by_server_pending, res);
754         goto out;
755       }
756       
757       /* Save the pointer to the client_entry pointer */
758       client_entry = (SilcClientEntry)server;
759     } else {
760       /* Find Channel entry */
761       silc_free(channel_id);
762       channel_id = id;
763       client_entry = (SilcClientEntry)
764         silc_client_get_channel_by_id(client, conn, channel_id);
765       if (!client_entry) {
766         silc_client_channel_set_wait(client, conn, channel,
767                                      conn->cmd_ident + 1);
768         silc_client_notify_by_server_resolve(client, conn, packet, 
769                                              SILC_ID_CHANNEL, channel_id);
770         goto out;
771       }
772     }
773
774     /* Get the mode */
775     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
776     if (!tmp)
777       goto out;
778
779     SILC_GET32_MSB(mode, tmp);
780
781     /* If information is being resolved for this channel, wait for it */
782     if (channel->resolve_cmd_ident) {
783       silc_client_channel_wait(client, conn, channel, packet);
784       goto out;
785     }
786
787     /* Save the new mode */
788     channel->mode = mode;
789
790     /* Get the hmac */
791     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
792     if (tmp) {
793       unsigned char hash[32];
794
795       if (channel->hmac)
796         silc_hmac_free(channel->hmac);
797       if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
798         goto out;
799
800       silc_hash_make(silc_hmac_get_hash(channel->hmac), 
801                      channel->key, channel->key_len / 8,
802                      hash);
803       silc_hmac_set_key(channel->hmac, hash, 
804                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
805       memset(hash, 0, sizeof(hash));
806     }
807
808     /* Notify application. The channel entry is sent last as this notify
809        is for channel but application don't know it from the arguments
810        sent by server. */
811     client->internal->ops->notify(client, conn, type, id_type,
812                                   client_entry, mode, NULL, tmp, channel);
813     break;
814
815   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
816     /*
817      * Someone changed user's mode on a channel
818      */
819
820     SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
821
822     /* Get channel entry */
823     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
824                                 SILC_ID_CHANNEL);
825     if (!channel_id)
826       goto out;
827     channel = silc_client_get_channel_by_id(client, conn, channel_id);
828     if (!channel)
829       break;
830
831     /* Get ID */
832     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
833     if (!tmp)
834       goto out;
835     id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
836     if (!id)
837       goto out;
838
839     /* Find Client entry */
840     if (id_type == SILC_ID_CLIENT) {
841       /* Find Client entry */
842       client_id = id;
843       client_entry = silc_client_get_client_by_id(client, conn, client_id);
844       if (!client_entry) {
845         silc_client_channel_set_wait(client, conn, channel,
846                                      conn->cmd_ident + 1);
847         silc_client_notify_by_server_resolve(client, conn, packet, 
848                                              SILC_ID_CLIENT, client_id);
849         goto out;
850       }
851     } else if (id_type == SILC_ID_SERVER) {
852       /* Find Server entry */
853       server_id = id;
854       server = silc_client_get_server_by_id(client, conn, server_id);
855       if (!server) {
856         silc_client_channel_set_wait(client, conn, channel,
857                                      conn->cmd_ident + 1);
858         silc_client_notify_by_server_resolve(client, conn, packet, 
859                                              SILC_ID_SERVER, server_id);
860         server = silc_client_add_server(client, conn, NULL, NULL, server_id);
861         if (!server)
862           goto out;
863
864         server->resolve_cmd_ident = conn->cmd_ident;
865         server_id = NULL;
866         goto out;
867       }
868
869       /* If entry being resoled, wait for it before processing this notify */
870       if (server->resolve_cmd_ident) {
871         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
872         res->packet = silc_packet_context_dup(packet);
873         res->context = client;
874         res->sock = silc_socket_dup(conn->sock);
875         silc_client_command_pending(conn, SILC_COMMAND_NONE, 
876                                     server->resolve_cmd_ident,
877                                     silc_client_notify_by_server_pending, res);
878         goto out;
879       }
880
881       /* Save the pointer to the client_entry pointer */
882       client_entry = (SilcClientEntry)server;
883     } else {
884       /* Find Channel entry */
885       silc_free(channel_id);
886       channel_id = id;
887       client_entry = (SilcClientEntry)
888         silc_client_get_channel_by_id(client, conn, channel_id);
889       if (!client_entry) {
890         silc_client_channel_set_wait(client, conn, channel,
891                                      conn->cmd_ident + 1);
892         silc_client_notify_by_server_resolve(client, conn, packet, 
893                                              SILC_ID_CHANNEL, channel_id);
894         goto out;
895       }
896     }
897
898     /* Get the mode */
899     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
900     if (!tmp)
901       goto out;
902
903     SILC_GET32_MSB(mode, tmp);
904
905     /* If information is being resolved for this channel, wait for it */
906     if (channel->resolve_cmd_ident) {
907       silc_client_channel_wait(client, conn, channel, packet);
908       goto out;
909     }
910
911     /* Get target Client ID */
912     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
913     if (!tmp)
914       goto out;
915
916     silc_free(client_id);
917     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
918     if (!client_id)
919       goto out;
920
921     /* Find target Client entry */
922     client_entry2 = 
923       silc_client_get_client_by_id(client, conn, client_id);
924     if (!client_entry2) {
925       silc_client_notify_by_server_resolve(client, conn, packet, 
926                                            SILC_ID_CLIENT, client_id);
927       goto out;
928     }
929
930     /* Save the mode */
931     chu = silc_client_on_channel(channel, client_entry2);
932     if (chu)
933       chu->mode = mode;
934
935     /* Notify application. The channel entry is sent last as this notify
936        is for channel but application don't know it from the arguments
937        sent by server. */
938     client->internal->ops->notify(client, conn, type,
939                                   id_type, client_entry, mode, 
940                                   client_entry2, channel);
941     break;
942
943   case SILC_NOTIFY_TYPE_MOTD:
944     /*
945      * Received Message of the day
946      */
947
948     SILC_LOG_DEBUG(("Notify: MOTD"));
949
950     /* Get motd */
951     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
952     if (!tmp)
953       goto out;
954     
955     /* Notify application */
956     client->internal->ops->notify(client, conn, type, tmp);
957     break;
958
959   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
960     /*
961      * Router has enforced a new ID to a channel. Let's change the old
962      * ID to the one provided here.
963      */
964
965     SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
966
967     /* Get the old ID */
968     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
969     if (!tmp)
970       goto out;
971     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
972     if (!channel_id)
973       goto out;
974
975     /* Get the channel entry */
976     channel = silc_client_get_channel_by_id(client, conn, channel_id);
977     if (!channel)
978       goto out;
979
980     silc_free(channel_id);
981
982     /* Get the new ID */
983     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
984     if (!tmp)
985       goto out;
986     channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
987     if (!channel_id)
988       goto out;
989
990     /* Replace the Channel ID */
991     if (silc_client_replace_channel_id(client, conn, channel, channel_id))
992       channel_id = NULL;
993
994     /* Notify application */
995     client->internal->ops->notify(client, conn, type, channel, channel);
996     break;
997
998   case SILC_NOTIFY_TYPE_KICKED:
999     /*
1000      * A client (maybe me) was kicked from a channel
1001      */
1002
1003     SILC_LOG_DEBUG(("Notify: KICKED"));
1004
1005     /* Get Client ID */
1006     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1007     if (!tmp)
1008       goto out;
1009
1010     client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1011     if (!client_id)
1012       goto out;
1013
1014     /* Find Client entry */
1015     client_entry = silc_client_get_client_by_id(client, conn, client_id);
1016     if (!client_entry)
1017       goto out;
1018
1019     /* Get channel entry */
1020     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1021                                 SILC_ID_CHANNEL);
1022     if (!channel_id)
1023       goto out;
1024     channel = silc_client_get_channel_by_id(client, conn, channel_id);
1025     if (!channel)
1026       break;
1027
1028     /* From protocol version 1.1 we get the kicker's client ID as well */
1029     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1030     if (tmp) {
1031       silc_free(client_id);
1032       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1033       if (!client_id)
1034         goto out;
1035
1036       /* Find kicker's client entry and if not found resolve it */
1037       client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1038       if (!client_entry2) {
1039         silc_client_notify_by_server_resolve(client, conn, packet, 
1040                                              SILC_ID_CLIENT, client_id);
1041         goto out;
1042       } else {
1043         if (client_entry2 != conn->local_entry)
1044           silc_client_nickname_format(client, conn, client_entry2);
1045       }
1046     }
1047
1048     /* Get comment */
1049     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1050
1051     /* Notify application. The channel entry is sent last as this notify
1052        is for channel but application don't know it from the arguments
1053        sent by server. */
1054     client->internal->ops->notify(client, conn, type, client_entry, tmp, 
1055                                   client_entry2, channel);
1056
1057     /* Remove kicked client from channel */
1058     if (client_entry == conn->local_entry) {
1059       /* If I was kicked from channel, remove the channel */
1060       if (conn->current_channel == channel)
1061         conn->current_channel = NULL;
1062       silc_client_del_channel(client, conn, channel);
1063     } else {
1064       chu = silc_client_on_channel(channel, client_entry);
1065       if (chu) {
1066         silc_hash_table_del(client_entry->channels, channel);
1067         silc_hash_table_del(channel->user_list, client_entry);
1068         silc_free(chu);
1069       }
1070
1071       if (!silc_hash_table_count(client_entry->channels)) {
1072         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1073         res->context = client;
1074         res->sock = silc_socket_dup(conn->sock);
1075         res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1076         silc_schedule_task_add(client->schedule, conn->sock->sock,
1077                                silc_client_notify_check_client, res,
1078                                (5 + (silc_rng_get_rn16(client->rng) % 529)),
1079                                0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1080       }
1081     }
1082     break;
1083
1084   case SILC_NOTIFY_TYPE_KILLED:
1085     {
1086       /*
1087        * A client (maybe me) was killed from the network.
1088        */
1089       char *comment;
1090       SilcUInt32 comment_len;
1091
1092       SILC_LOG_DEBUG(("Notify: KILLED"));
1093
1094       /* Get Client ID */
1095       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1096       if (!tmp)
1097         goto out;
1098
1099       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1100       if (!client_id)
1101         goto out;
1102
1103       /* Find Client entry */
1104       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1105       if (!client_entry)
1106         goto out;
1107
1108       /* Get comment */
1109       comment = silc_argument_get_arg_type(args, 2, &comment_len);
1110
1111       /* From protocol version 1.1 we get killer's client ID as well */
1112       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1113       if (tmp) {
1114         silc_free(client_id);
1115         id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1116         if (!id)
1117           goto out;
1118
1119         /* Find Client entry */
1120         if (id_type == SILC_ID_CLIENT) {
1121           /* Find Client entry */
1122           client_id = id;
1123           client_entry2 = silc_client_get_client_by_id(client, conn, 
1124                                                        client_id);
1125           if (!client_entry) {
1126             silc_client_notify_by_server_resolve(client, conn, packet, 
1127                                                  SILC_ID_CLIENT, client_id);
1128             goto out;
1129           }
1130         } else if (id_type == SILC_ID_SERVER) {
1131           /* Find Server entry */
1132           server_id = id;
1133           server = silc_client_get_server_by_id(client, conn, server_id);
1134           if (!server) {
1135             silc_client_notify_by_server_resolve(client, conn, packet, 
1136                                                  SILC_ID_SERVER, server_id);
1137             server = silc_client_add_server(client, conn, NULL, NULL,
1138                                             server_id);
1139             if (!server)
1140               goto out;
1141
1142             server->resolve_cmd_ident = conn->cmd_ident;
1143             server_id = NULL;
1144             goto out;
1145           }
1146
1147           if (server->resolve_cmd_ident) {
1148             SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1149             res->packet = silc_packet_context_dup(packet);
1150             res->context = client;
1151             res->sock = silc_socket_dup(conn->sock);
1152             silc_client_command_pending(conn, SILC_COMMAND_NONE, 
1153                                         server->resolve_cmd_ident,
1154                                         silc_client_notify_by_server_pending,
1155                                         res);
1156             goto out;
1157           }
1158       
1159           /* Save the pointer to the client_entry pointer */
1160           client_entry2 = (SilcClientEntry)server;
1161         } else {
1162           /* Find Channel entry */
1163           channel_id = id;
1164           channel = silc_client_get_channel_by_id(client, conn, channel_id);
1165           if (!channel) {
1166             silc_client_notify_by_server_resolve(client, conn, packet, 
1167                                                  SILC_ID_CHANNEL, channel_id);
1168             goto out;
1169           }
1170           
1171           /* Save the pointer to the client_entry pointer */
1172           client_entry2 = (SilcClientEntry)channel;
1173           silc_free(channel_id);
1174           channel_id = NULL;
1175         }
1176       }
1177
1178       /* Notify application. */
1179       client->internal->ops->notify(client, conn, type, client_entry, 
1180                                     comment, id_type, client_entry2);
1181
1182       if (client_entry != conn->local_entry)
1183         /* Remove the client from all channels and free it */
1184         silc_client_del_client(client, conn, client_entry);
1185     }
1186     break;
1187     
1188   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1189     {
1190       /*
1191        * A server quit the SILC network and some clients must be removed
1192        * from channels as they quit as well.
1193        */
1194       SilcClientEntry *clients = NULL;
1195       SilcUInt32 clients_count = 0;
1196       int i;
1197
1198       SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1199
1200       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1201         /* Get Client ID */
1202         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1203         if (tmp) {
1204           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1205           if (!client_id)
1206             goto out;
1207           
1208           /* Get the client entry */
1209           client_entry = silc_client_get_client_by_id(client, conn, client_id);
1210           if (client_entry) {
1211             clients = silc_realloc(clients, sizeof(*clients) * 
1212                                    (clients_count + 1));
1213             clients[clients_count] = client_entry;
1214             clients_count++;
1215           }
1216           silc_free(client_id);
1217         }
1218       }
1219       client_id = NULL;
1220
1221       /* Notify application. We don't keep server entries so the server
1222          entry is returned as NULL. The client's are returned as array
1223          of SilcClientEntry pointers. */
1224       client->internal->ops->notify(client, conn, type, NULL, 
1225                                     clients, clients_count);
1226
1227       for (i = 0; i < clients_count; i++) {
1228         /* Remove client from all channels */
1229         client_entry = clients[i];
1230         if (client_entry == conn->local_entry)
1231           continue;
1232
1233         /* Remove the client from all channels and free it */
1234         silc_client_del_client(client, conn, client_entry);
1235       }
1236       silc_free(clients);
1237
1238     }
1239     break;
1240
1241   case SILC_NOTIFY_TYPE_ERROR:
1242     {
1243       /*
1244        * Some has occurred and server is notifying us about it.
1245        */
1246       SilcStatus error;
1247
1248       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1249       if (!tmp && tmp_len != 1)
1250         goto out;
1251       error = (SilcStatus)tmp[0];
1252
1253       SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1254
1255       if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1256         tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1257         if (tmp) {
1258           client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1259           if (!client_id)
1260             goto out;
1261           client_entry = silc_client_get_client_by_id(client, conn,
1262                                                       client_id);
1263           if (client_entry)
1264             silc_client_del_client(client, conn, client_entry);
1265         }
1266       }
1267
1268       /* Notify application. */
1269       client->internal->ops->notify(client, conn, type, error);
1270     }
1271     break;
1272
1273   case SILC_NOTIFY_TYPE_WATCH:
1274     {
1275       /*
1276        * Received notify about some client we are watching
1277        */
1278       SilcNotifyType notify = 0;
1279       bool del_client = FALSE;
1280
1281       SILC_LOG_DEBUG(("Notify: WATCH"));
1282
1283       /* Get sender Client ID */
1284       tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1285       if (!tmp)
1286         goto out;
1287       client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1288       if (!client_id)
1289         goto out;
1290
1291       /* Find Client entry and if not found query it */
1292       client_entry = silc_client_get_client_by_id(client, conn, client_id);
1293       if (!client_entry) {
1294         silc_client_notify_by_server_resolve(client, conn, packet, 
1295                                              SILC_ID_CLIENT, client_id);
1296         goto out;
1297       }
1298
1299       /* Get user mode */
1300       tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1301       if (!tmp || tmp_len != 4)
1302         goto out;
1303       SILC_GET32_MSB(mode, tmp);
1304
1305       /* Get notify type */
1306       tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1307       if (tmp && tmp_len != 2)
1308         goto out;
1309       if (tmp)
1310         SILC_GET16_MSB(notify, tmp);
1311
1312       /* Get nickname */
1313       tmp = silc_argument_get_arg_type(args, 2, NULL);
1314       if (tmp) {
1315         char *tmp_nick = NULL;
1316
1317         if (client->internal->params->nickname_parse)
1318           client->internal->params->nickname_parse(client_entry->nickname,
1319                                                    &tmp_nick);
1320         else
1321           tmp_nick = strdup(tmp);
1322
1323         /* If same nick, the client was new to us and has become "present"
1324            to network.  Send NULL as nick to application. */
1325         if (tmp_nick && !strcmp(tmp, tmp_nick))
1326           tmp = NULL;
1327
1328         silc_free(tmp_nick);
1329       }
1330
1331       /* Notify application. */
1332       client->internal->ops->notify(client, conn, type, client_entry,
1333                                     tmp, mode, notify);
1334
1335       client_entry->mode = mode;
1336
1337       /* If nickname was changed, remove the client entry unless the
1338          client is on some channel */
1339       if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1340           !silc_hash_table_count(client_entry->channels))
1341         del_client = TRUE;
1342       else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1343                notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1344                notify == SILC_NOTIFY_TYPE_KILLED)
1345         del_client = TRUE;
1346
1347       if (del_client) {
1348         SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1349         res->context = client;
1350         res->sock = silc_socket_dup(conn->sock);
1351         res->packet = client_id;
1352         client_id = NULL;
1353         silc_schedule_task_add(client->schedule, conn->sock->sock,
1354                                silc_client_notify_del_client_cb, res,
1355                                1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1356       }
1357     }
1358     break;
1359
1360   default:
1361     break;
1362   }
1363
1364  out:
1365   silc_notify_payload_free(payload);
1366   silc_free(client_id);
1367   silc_free(channel_id);
1368   silc_free(server_id);
1369 }