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