updates.
[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 - 2001 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* $Id$ */
21 /* This file includes the Notify packet handling. Notify packets are
22    important packets sent by the server. They tell different things to the
23    client such as nick changes, mode changes etc. */
24
25 #include "clientlibincludes.h"
26 #include "client_internal.h"
27
28 typedef struct {
29   SilcPacketContext *packet;
30   void *context;
31   SilcSocketConnection sock;
32 } *SilcClientNotifyResolve;
33
34 /* Called when notify is received and some async operation (such as command)
35    is required before processing the notify message. This calls again the
36    silc_client_notify_by_server and reprocesses the original notify packet. */
37
38 static void silc_client_notify_by_server_pending(void *context, void *context2)
39 {
40   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
41   SilcClientCommandReplyContext reply = 
42     (SilcClientCommandReplyContext)context2;
43
44   if (reply) {
45     SilcCommandStatus status;
46     unsigned char *tmp = silc_argument_get_arg_type(reply->args, 1, NULL);
47     SILC_GET16_MSB(status, tmp);
48     if (status != SILC_STATUS_OK) {
49       silc_socket_free(res->sock);
50       return;
51     }
52   }
53
54   silc_client_notify_by_server(res->context, res->sock, res->packet);
55   silc_socket_free(res->sock);
56 }
57
58 /* Destructor for the pending command callback */
59
60 static void silc_client_notify_by_server_destructor(void *context)
61 {
62   SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
63   silc_packet_context_free(res->packet);
64   silc_free(res);
65 }
66
67 /* Resolve client information from server by Client ID. */
68
69 static void silc_client_notify_by_server_resolve(SilcClient client,
70                                                  SilcClientConnection conn,
71                                                  SilcPacketContext *packet,
72                                                  SilcClientID *client_id)
73 {
74   SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
75   SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
76
77   res->packet = silc_packet_context_dup(packet);
78   res->context = client;
79   res->sock = silc_socket_dup(conn->sock);
80
81   silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, ++conn->cmd_ident,
82                            1, 3, idp->data, idp->len);
83   silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
84                               silc_client_notify_by_server_destructor,
85                               silc_client_notify_by_server_pending, res);
86   silc_buffer_free(idp);
87 }
88
89 /* Received notify message from server */
90
91 void silc_client_notify_by_server(SilcClient client,
92                                   SilcSocketConnection sock,
93                                   SilcPacketContext *packet)
94 {
95   SilcBuffer buffer = packet->buffer;
96   SilcClientConnection conn = (SilcClientConnection)sock->user_data;
97   SilcNotifyPayload payload;
98   SilcNotifyType type;
99   SilcArgumentPayload args;
100
101   SilcIDPayload idp;
102   SilcClientID *client_id = NULL;
103   SilcChannelID *channel_id = NULL;
104   SilcServerID *server_id = NULL;
105   SilcClientEntry client_entry;
106   SilcClientEntry client_entry2;
107   SilcChannelEntry channel;
108   SilcChannelUser chu;
109   SilcServerEntry server;
110   SilcIDCacheEntry id_cache = NULL;
111   unsigned char *tmp;
112   uint32 tmp_len, mode;
113
114   SILC_LOG_DEBUG(("Start"));
115
116   payload = silc_notify_payload_parse(buffer->data, buffer->len);
117   if (!payload)
118     goto out;
119
120   type = silc_notify_get_type(payload);
121   args = silc_notify_get_args(payload);
122   if (!args)
123     goto out;
124
125   switch(type) {
126   case SILC_NOTIFY_TYPE_NONE:
127     /* Notify application */
128     client->ops->notify(client, conn, type, 
129                         silc_argument_get_arg_type(args, 1, NULL));
130     break;
131
132   case SILC_NOTIFY_TYPE_INVITE:
133     /* 
134      * Someone invited me to a channel. Find Client and Channel entries
135      * for the application.
136      */
137     
138     SILC_LOG_DEBUG(("Notify: INVITE"));
139
140     /* Get Channel ID */
141     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
142     if (!tmp)
143       goto out;
144
145     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
146     if (!channel_id)
147       goto out;
148
149     /* Get the channel entry */
150     channel = NULL;
151     if (silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
152                                     &id_cache))
153       channel = (SilcChannelEntry)id_cache->context;
154
155     /* Get sender Client ID */
156     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
157     if (!tmp)
158       goto out;
159
160     client_id = silc_id_payload_parse_id(tmp, tmp_len);
161     if (!client_id)
162       goto out;
163
164     /* Find Client entry and if not found query it */
165     client_entry = silc_client_get_client_by_id(client, conn, client_id);
166     if (!client_entry) {
167       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
168       goto out;
169     }
170
171     /* Get the channel name */
172     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
173     if (!tmp)
174       goto out;
175
176     /* Notify application */
177     client->ops->notify(client, conn, type, channel, tmp, client_entry);
178     break;
179
180   case SILC_NOTIFY_TYPE_JOIN:
181     /*
182      * Someone has joined to a channel. Get their ID and nickname and
183      * cache them for later use.
184      */
185
186     SILC_LOG_DEBUG(("Notify: JOIN"));
187
188     /* Get Client ID */
189     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
190     if (!tmp)
191       goto out;
192
193     client_id = silc_id_payload_parse_id(tmp, tmp_len);
194     if (!client_id)
195       goto out;
196
197     /* Find Client entry and if not found query it */
198     client_entry = silc_client_get_client_by_id(client, conn, client_id);
199     if (!client_entry) {
200       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
201       goto out;
202     }
203
204     /* If nickname or username hasn't been resolved, do so */
205     if (!client_entry->nickname || !client_entry->username) {
206       if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
207         client_entry->status &= ~SILC_CLIENT_STATUS_RESOLVING;
208         goto out;
209       }
210       client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
211       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
212       goto out;
213     } else {
214       if (client_entry != conn->local_entry)
215         silc_client_nickname_format(client, conn, client_entry);
216     }
217
218     /* Get Channel ID */
219     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
220     if (!tmp)
221       goto out;
222
223     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
224     if (!channel_id)
225       goto out;
226
227     /* Get channel entry */
228     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
229                                      &id_cache))
230       break;
231
232     channel = (SilcChannelEntry)id_cache->context;
233
234     /* Add client to channel */
235     if (client_entry != conn->local_entry) {
236       chu = silc_calloc(1, sizeof(*chu));
237       chu->client = client_entry;
238       silc_list_add(channel->clients, chu);
239     }
240
241     /* Notify application. The channel entry is sent last as this notify
242        is for channel but application don't know it from the arguments
243        sent by server. */
244     client->ops->notify(client, conn, type, client_entry, channel);
245     break;
246
247   case SILC_NOTIFY_TYPE_LEAVE:
248     /*
249      * Someone has left a channel. We will remove it from the channel but
250      * we'll keep it in the cache in case we'll need it later.
251      */
252     
253     SILC_LOG_DEBUG(("Notify: LEAVE"));
254
255     /* Get Client ID */
256     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
257     if (!tmp)
258       goto out;
259
260     client_id = silc_id_payload_parse_id(tmp, tmp_len);
261     if (!client_id)
262       goto out;
263
264     /* Find Client entry */
265     client_entry = 
266       silc_client_get_client_by_id(client, conn, client_id);
267     if (!client_entry)
268       goto out;
269
270     /* Get channel entry */
271     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
272                                 SILC_ID_CHANNEL);
273     if (!channel_id)
274       goto out;
275     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
276                                  &id_cache))
277       break;
278
279     channel = (SilcChannelEntry)id_cache->context;
280
281     /* Remove client from channel */
282     silc_list_start(channel->clients);
283     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
284       if (chu->client == client_entry) {
285         silc_list_del(channel->clients, chu);
286         silc_free(chu);
287         break;
288       }
289     }
290
291     /* Notify application. The channel entry is sent last as this notify
292        is for channel but application don't know it from the arguments
293        sent by server. */
294     client->ops->notify(client, conn, type, client_entry, channel);
295     break;
296
297   case SILC_NOTIFY_TYPE_SIGNOFF:
298     /*
299      * Someone left SILC. We'll remove it from all channels and from cache.
300      */
301
302     SILC_LOG_DEBUG(("Notify: SIGNOFF"));
303
304     /* Get Client ID */
305     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
306     if (!tmp)
307       goto out;
308
309     client_id = silc_id_payload_parse_id(tmp, tmp_len);
310     if (!client_id)
311       goto out;
312
313     /* Find Client entry */
314     client_entry = 
315       silc_client_get_client_by_id(client, conn, client_id);
316     if (!client_entry)
317       goto out;
318
319     /* Remove from all channels */
320     silc_client_remove_from_channels(client, conn, client_entry);
321
322     /* Remove from cache */
323     silc_idcache_del_by_context(conn->client_cache, client_entry);
324
325     /* Get signoff message */
326     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
327     if (tmp_len > 128)
328       tmp = NULL;
329
330     /* Notify application */
331     client->ops->notify(client, conn, type, client_entry, tmp);
332
333     /* Free data */
334     silc_client_del_client_entry(client, conn, client_entry);
335     break;
336
337   case SILC_NOTIFY_TYPE_TOPIC_SET:
338     /*
339      * Someone set the topic on a channel.
340      */
341
342     SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
343
344     /* Get Client ID */
345     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
346     if (!tmp)
347       goto out;
348
349     client_id = silc_id_payload_parse_id(tmp, tmp_len);
350     if (!client_id)
351       goto out;
352
353     /* Find Client entry */
354     client_entry = 
355       silc_client_get_client_by_id(client, conn, client_id);
356     if (!client_entry)
357       goto out;
358
359     /* Get topic */
360     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
361     if (!tmp)
362       goto out;
363
364     /* Get channel entry */
365     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
366                                 SILC_ID_CHANNEL);
367     if (!channel_id)
368       goto out;
369     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
370                                  &id_cache))
371       break;
372
373     channel = (SilcChannelEntry)id_cache->context;
374
375     /* Notify application. The channel entry is sent last as this notify
376        is for channel but application don't know it from the arguments
377        sent by server. */
378     client->ops->notify(client, conn, type, client_entry, tmp, channel);
379     break;
380
381   case SILC_NOTIFY_TYPE_NICK_CHANGE:
382     /*
383      * Someone changed their nickname. If we don't have entry for the new
384      * ID we will query it and return here after it's done. After we've
385      * returned we fetch the old entry and free it and notify the 
386      * application.
387      */
388
389     SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
390
391     /* Get old Client ID */
392     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
393     if (!tmp)
394       goto out;
395
396     client_id = silc_id_payload_parse_id(tmp, tmp_len);
397     if (!client_id)
398       goto out;
399
400     /* Ignore my ID */
401     if (SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
402       break;
403
404     /* Find old Client entry */
405     client_entry = silc_client_get_client_by_id(client, conn, client_id);
406     if (!client_entry)
407       goto out;
408     silc_free(client_id);
409
410     client_entry->valid = FALSE;
411
412     /* Get new Client ID */
413     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
414     if (!tmp)
415       goto out;
416
417     client_id = silc_id_payload_parse_id(tmp, tmp_len);
418     if (!client_id)
419       goto out;
420
421     /* Find Client entry and if not found resolve it */
422     client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
423     if (!client_entry2) {
424       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
425       goto out;
426     } else {
427       if (client_entry2 != conn->local_entry)
428         silc_client_nickname_format(client, conn, client_entry2);
429     }
430
431     /* Remove the old from cache */
432     silc_idcache_del_by_context(conn->client_cache, client_entry);
433
434     /* Replace old ID entry with new one on all channels. */
435     silc_client_replace_from_channels(client, conn, client_entry,
436                                       client_entry2);
437
438     /* Notify application */
439     client->ops->notify(client, conn, type, client_entry, client_entry2);
440
441     /* Free data */
442     silc_client_del_client_entry(client, conn, client_entry);
443     break;
444
445   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
446     /*
447      * Someone changed a channel mode
448      */
449
450     SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
451
452     /* Get Client ID */
453     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
454     if (!tmp)
455       goto out;
456
457     idp = silc_id_payload_parse(tmp, tmp_len);
458     if (!idp)
459       goto out;
460
461     /* Find Client entry */
462     if (silc_id_payload_get_type(idp) == SILC_ID_CLIENT) {
463       client_id = silc_id_payload_parse_id(tmp, tmp_len);
464       if (!client_id) {
465         silc_id_payload_free(idp);
466         goto out;
467       }
468
469       client_entry = silc_client_get_client_by_id(client, conn, client_id);
470       if (!client_entry) {
471         silc_id_payload_free(idp);
472         goto out;
473       }
474     } else {
475       server_id = silc_id_payload_parse_id(tmp, tmp_len);
476       if (!server_id) {
477         silc_id_payload_free(idp);
478         goto out;
479       }
480       
481       server = silc_client_get_server_by_id(client, conn, server_id);
482       if (!server) {
483         silc_id_payload_free(idp);
484         silc_free(server_id);
485         goto out;
486       }
487       
488       /* Save the pointer to the client_entry pointer */
489       client_entry = (SilcClientEntry)server;
490       silc_free(server_id);
491     }
492
493     /* Get the mode */
494     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
495     if (!tmp) {
496       silc_id_payload_free(idp);
497       goto out;
498     }
499
500     SILC_GET32_MSB(mode, tmp);
501
502     /* Get channel entry */
503     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
504                                 SILC_ID_CHANNEL);
505     if (!channel_id) {
506       silc_id_payload_free(idp);
507       goto out;
508     }
509     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
510                                      &id_cache)) {
511       silc_id_payload_free(idp);
512       goto out;
513     }
514
515     channel = (SilcChannelEntry)id_cache->context;
516
517     /* Save the new mode */
518     channel->mode = mode;
519
520     /* Get the hmac */
521     tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
522     if (tmp) {
523       unsigned char hash[32];
524
525       if (channel->hmac)
526         silc_hmac_free(channel->hmac);
527       if (!silc_hmac_alloc(tmp, NULL, &channel->hmac))
528         goto out;
529
530       silc_hash_make(silc_hmac_get_hash(channel->hmac), 
531                      channel->key, channel->key_len / 8,
532                      hash);
533       silc_hmac_set_key(channel->hmac, hash, 
534                         silc_hash_len(silc_hmac_get_hash(channel->hmac)));
535       memset(hash, 0, sizeof(hash));
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->ops->notify(client, conn, type, silc_id_payload_get_type(idp), 
542                         client_entry, mode, NULL, tmp, channel);
543
544     silc_id_payload_free(idp);
545     break;
546
547   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
548     /*
549      * Someone changed user's mode on a channel
550      */
551
552     SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
553
554     /* Get Client ID */
555     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
556     if (!tmp)
557       goto out;
558
559     client_id = silc_id_payload_parse_id(tmp, tmp_len);
560     if (!client_id)
561       goto out;
562
563     /* Find Client entry */
564     client_entry = silc_client_get_client_by_id(client, conn, client_id);
565     if (!client_entry) {
566       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
567       goto out;
568     }
569
570     /* Get the mode */
571     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
572     if (!tmp)
573       goto out;
574
575     SILC_GET32_MSB(mode, tmp);
576
577     /* Get target Client ID */
578     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
579     if (!tmp)
580       goto out;
581
582     silc_free(client_id);
583     client_id = silc_id_payload_parse_id(tmp, tmp_len);
584     if (!client_id)
585       goto out;
586
587     /* Find target Client entry */
588     client_entry2 = 
589       silc_client_get_client_by_id(client, conn, client_id);
590     if (!client_entry2)
591       goto out;
592
593     /* Get channel entry */
594     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
595                                 SILC_ID_CHANNEL);
596     if (!channel_id)
597       goto out;
598     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
599                                  &id_cache))
600       break;
601
602     channel = (SilcChannelEntry)id_cache->context;
603
604     /* Save the mode */
605     silc_list_start(channel->clients);
606     while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
607       if (chu->client == client_entry) {
608         chu->mode = mode;
609         break;
610       }
611     }
612
613     /* Notify application. The channel entry is sent last as this notify
614        is for channel but application don't know it from the arguments
615        sent by server. */
616     client->ops->notify(client, conn, type, client_entry, mode, 
617                         client_entry2, channel);
618     break;
619
620   case SILC_NOTIFY_TYPE_MOTD:
621     /*
622      * Received Message of the day
623      */
624
625     SILC_LOG_DEBUG(("Notify: MOTD"));
626
627     /* Get motd */
628     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
629     if (!tmp)
630       goto out;
631     
632     /* Notify application */
633     client->ops->notify(client, conn, type, tmp);
634     break;
635
636   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
637     /*
638      * Router has enforced a new ID to a channel. Let's change the old
639      * ID to the one provided here.
640      */
641
642     SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
643
644     /* Get the old ID */
645     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
646     if (!tmp)
647       goto out;
648     channel_id = silc_id_payload_parse_id(tmp, tmp_len);
649     if (!channel_id)
650       goto out;
651     
652     /* Get the channel entry */
653     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
654                                      &id_cache))
655       break;
656
657     channel = (SilcChannelEntry)id_cache->context;
658
659     SILC_LOG_DEBUG(("Old Channel ID id(%s)", 
660                     silc_id_render(channel->id, SILC_ID_CHANNEL)));
661
662     /* Free the old ID */
663     silc_free(channel->id);
664
665     /* Get the new ID */
666     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
667     if (!tmp)
668       goto out;
669     channel->id = silc_id_payload_parse_id(tmp, tmp_len);
670     if (!channel->id)
671       goto out;
672
673     SILC_LOG_DEBUG(("New Channel ID id(%s)", 
674                     silc_id_render(channel->id, SILC_ID_CHANNEL)));
675
676     /* Remove the old cache entry and create a new one */
677     silc_idcache_del_by_context(conn->channel_cache, channel);
678     silc_idcache_add(conn->channel_cache, channel->channel_name, 
679                      channel->id, channel, FALSE);
680
681     /* Notify application */
682     client->ops->notify(client, conn, type, channel, channel);
683     break;
684
685   case SILC_NOTIFY_TYPE_KICKED:
686     /*
687      * A client (maybe me) was kicked from a channel
688      */
689
690     SILC_LOG_DEBUG(("Notify: KICKED"));
691
692     /* Get Client ID */
693     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
694     if (!tmp)
695       goto out;
696
697     client_id = silc_id_payload_parse_id(tmp, tmp_len);
698     if (!client_id)
699       goto out;
700
701     /* Find Client entry */
702     client_entry = silc_client_get_client_by_id(client, conn, client_id);
703     if (!client_entry)
704       goto out;
705
706     /* Get channel entry */
707     channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
708                                 SILC_ID_CHANNEL);
709     if (!channel_id)
710       goto out;
711     if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
712                                      &id_cache))
713       break;
714
715     channel = (SilcChannelEntry)id_cache->context;
716
717     /* Get the kicker */
718     tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
719     if (!tmp)
720       goto out;
721
722     client_id = silc_id_payload_parse_id(tmp, tmp_len);
723     if (!client_id)
724       goto out;
725
726     /* Find kicker's client entry and if not found resolve it */
727     client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
728     if (!client_entry2) {
729       silc_client_notify_by_server_resolve(client, conn, packet, client_id);
730       goto out;
731     } else {
732       if (client_entry2 != conn->local_entry)
733         silc_client_nickname_format(client, conn, client_entry2);
734     }
735
736     /* Get comment */
737     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
738
739     /* Notify application. The channel entry is sent last as this notify
740        is for channel but application don't know it from the arguments
741        sent by server. */
742     client->ops->notify(client, conn, type, client_entry, tmp, 
743                         client_entry2, channel);
744
745     /* If I was kicked from channel, remove the channel */
746     if (client_entry == conn->local_entry) {
747       if (conn->current_channel == channel)
748         conn->current_channel = NULL;
749       silc_idcache_del_by_id(conn->channel_cache, channel->id);
750       silc_free(channel->channel_name);
751       silc_free(channel->id);
752       silc_free(channel->key);
753       silc_cipher_free(channel->channel_key);
754       silc_free(channel);
755     }
756     break;
757
758   case SILC_NOTIFY_TYPE_KILLED:
759     /*
760      * A client (maybe me) was killed from the network.
761      */
762
763     SILC_LOG_DEBUG(("Notify: KILLED"));
764
765     /* Get Client ID */
766     tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
767     if (!tmp)
768       goto out;
769
770     client_id = silc_id_payload_parse_id(tmp, tmp_len);
771     if (!client_id)
772       goto out;
773
774     /* Find Client entry */
775     client_entry = silc_client_get_client_by_id(client, conn, client_id);
776     if (!client_entry)
777       goto out;
778
779     /* Get comment */
780     tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
781
782     /* Notify application. */
783     client->ops->notify(client, conn, type, client_entry, tmp);
784
785     if (client_entry != conn->local_entry) {
786       /* Remove client from all channels */
787       silc_client_remove_from_channels(client, conn, client_entry);
788       silc_client_del_client(client, conn, client_entry);
789     }
790
791     break;
792     
793   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
794     {
795       /*
796        * A server quit the SILC network and some clients must be removed
797        * from channels as they quit as well.
798        */
799       SilcClientEntry *clients = NULL;
800       uint32 clients_count = 0;
801       int i;
802
803       SILC_LOG_DEBUG(("Notify: SIGNOFF"));
804
805       for (i = 1; i < silc_argument_get_arg_num(args); i++) {
806         /* Get Client ID */
807         tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
808         if (tmp) {
809           client_id = silc_id_payload_parse_id(tmp, tmp_len);
810           if (!client_id)
811             goto out;
812           
813           /* Get the client entry */
814           client_entry = silc_client_get_client_by_id(client, conn, client_id);
815           if (client_entry) {
816             clients = silc_realloc(clients, sizeof(*clients) * 
817                                    (clients_count + 1));
818             clients[clients_count] = client_entry;
819             clients_count++;
820           }
821           silc_free(client_id);
822         }
823       }
824       client_id = NULL;
825
826       /* Notify application. We don't keep server entries so the server
827          entry is returned as NULL. The client's are returned as array
828          of SilcClientEntry pointers. */
829       client->ops->notify(client, conn, type, NULL, clients, clients_count);
830
831       for (i = 0; i < clients_count; i++) {
832         /* Remove client from all channels */
833         client_entry = clients[i];
834         if (client_entry == conn->local_entry)
835           continue;
836
837         silc_client_remove_from_channels(client, conn, client_entry);
838         silc_client_del_client(client, conn, client_entry);
839       }
840       silc_free(clients);
841
842     }
843     break;
844
845   default:
846     break;
847   }
848
849  out:
850   silc_notify_payload_free(payload);
851   silc_free(client_id);
852   silc_free(channel_id);
853 }