Rewrote file transfer.
[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 - 2007 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
21 #include "silc.h"
22 #include "silcclient.h"
23 #include "client_internal.h"
24
25 /************************** Types and definitions ***************************/
26
27 #define NOTIFY conn->client->internal->ops->notify
28
29 /* Notify processing context */
30 typedef struct {
31   SilcPacket packet;                  /* Notify packet */
32   SilcNotifyPayload payload;          /* Parsed notify payload */
33   SilcFSMThread fsm;                  /* Notify FSM thread */
34   SilcChannelEntry channel;           /* Channel entry being resolved */
35   SilcClientEntry client_entry;       /* Client entry being resolved */
36 } *SilcClientNotify;
37
38 /************************ Static utility functions **************************/
39
40 /* The client entires in notify processing are resolved if they do not exist,
41    or they are not valid.  We go to this callback after resolving where we
42    check if the client entry has become valid.  If resolving succeeded the
43    entry is valid but remains invalid if resolving failed.  This callback
44    will continue processing the notify.  We use this callback also with other
45    entry resolving. */
46
47 static void silc_client_notify_resolved(SilcClient client,
48                                         SilcClientConnection conn,
49                                         SilcStatus status,
50                                         SilcDList entries,
51                                         void *context)
52 {
53   SilcClientNotify notify = context;
54
55   /* If entry is still invalid, resolving failed.  Finish notify processing. */
56   if (notify->client_entry && !notify->client_entry->internal.valid) {
57     silc_fsm_next(notify->fsm, silc_client_notify_processed);
58     silc_client_unref_client(client, conn, notify->client_entry);
59   }
60
61   /* If no entries found, just finish the notify processing */
62   if (!entries && !notify->client_entry)
63     silc_fsm_next(notify->fsm, silc_client_notify_processed);
64
65   if (notify->channel) {
66     notify->channel->internal.resolve_cmd_ident = 0;
67     silc_client_unref_channel(client, conn, notify->channel);
68   }
69
70   /* Continue processing the notify */
71   SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
72 }
73
74 /* Continue notify processing after it was suspended while waiting for
75    channel information being resolved. */
76
77 static SilcBool silc_client_notify_wait_continue(SilcClient client,
78                                                  SilcClientConnection conn,
79                                                  SilcCommand command,
80                                                  SilcStatus status,
81                                                  SilcStatus error,
82                                                  void *context,
83                                                  va_list ap)
84 {
85   SilcClientNotify notify = context;
86
87   /* Continue after last command reply received */
88   if (SILC_STATUS_IS_ERROR(status) || status == SILC_STATUS_OK ||
89       status == SILC_STATUS_LIST_END)
90     SILC_FSM_CALL_CONTINUE_SYNC(notify->fsm);
91
92   return TRUE;
93 }
94
95 /********************************* Notify ***********************************/
96
97 /* Process received notify packet */
98
99 SILC_FSM_STATE(silc_client_notify)
100 {
101   SilcPacket packet = state_context;
102   SilcClientNotify notify;
103   SilcNotifyPayload payload;
104
105   payload = silc_notify_payload_parse(silc_buffer_data(&packet->buffer),
106                                       silc_buffer_len(&packet->buffer));
107   if (!payload) {
108     SILC_LOG_DEBUG(("Malformed notify payload"));
109     silc_packet_free(packet);
110     return SILC_FSM_FINISH;
111   }
112
113   if (!silc_notify_get_args(payload)) {
114     SILC_LOG_DEBUG(("Malformed notify %d", silc_notify_get_type(payload)));
115     silc_notify_payload_free(payload);
116     silc_packet_free(packet);
117     return SILC_FSM_FINISH;
118   }
119
120   notify = silc_calloc(1, sizeof(*notify));
121   if (!notify) {
122     silc_notify_payload_free(payload);
123     silc_packet_free(packet);
124     return SILC_FSM_FINISH;
125   }
126
127   notify->packet = packet;
128   notify->payload = payload;
129   notify->fsm = fsm;
130   silc_fsm_set_state_context(fsm, notify);
131
132   /* Process the notify */
133   switch (silc_notify_get_type(payload)) {
134
135   case SILC_NOTIFY_TYPE_NONE:
136     /** NONE */
137     silc_fsm_next(fsm, silc_client_notify_none);
138     break;
139
140   case SILC_NOTIFY_TYPE_INVITE:
141     /** INVITE */
142     silc_fsm_next(fsm, silc_client_notify_invite);
143     break;
144
145   case SILC_NOTIFY_TYPE_JOIN:
146     /** JOIN */
147     silc_fsm_next(fsm, silc_client_notify_join);
148     break;
149
150   case SILC_NOTIFY_TYPE_LEAVE:
151     /** LEAVE */
152     silc_fsm_next(fsm, silc_client_notify_leave);
153     break;
154
155   case SILC_NOTIFY_TYPE_SIGNOFF:
156     /** SIGNOFF */
157     silc_fsm_next(fsm, silc_client_notify_signoff);
158     break;
159
160   case SILC_NOTIFY_TYPE_TOPIC_SET:
161     /** TOPIC_SET */
162     silc_fsm_next(fsm, silc_client_notify_topic_set);
163     break;
164
165   case SILC_NOTIFY_TYPE_NICK_CHANGE:
166     /** NICK_CHANGE */
167     silc_fsm_next(fsm, silc_client_notify_nick_change);
168     break;
169
170   case SILC_NOTIFY_TYPE_CMODE_CHANGE:
171     /** CMODE_CHANGE */
172     silc_fsm_next(fsm, silc_client_notify_cmode_change);
173     break;
174
175   case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
176     /** CUMODE_CHANGE */
177     silc_fsm_next(fsm, silc_client_notify_cumode_change);
178     break;
179
180   case SILC_NOTIFY_TYPE_MOTD:
181     /** MOTD */
182     silc_fsm_next(fsm, silc_client_notify_motd);
183     break;
184
185   case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
186     /** CHANNEL_CHANGE */
187     silc_fsm_next(fsm, silc_client_notify_channel_change);
188     break;
189
190   case SILC_NOTIFY_TYPE_KICKED:
191     /** KICKED */
192     silc_fsm_next(fsm, silc_client_notify_kicked);
193     break;
194
195   case SILC_NOTIFY_TYPE_KILLED:
196     /** KILLED */
197     silc_fsm_next(fsm, silc_client_notify_killed);
198     break;
199
200   case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
201     /** SERVER_SIGNOFF */
202     silc_fsm_next(fsm, silc_client_notify_server_signoff);
203     break;
204
205   case SILC_NOTIFY_TYPE_ERROR:
206     /** ERROR */
207     silc_fsm_next(fsm, silc_client_notify_error);
208     break;
209
210   case SILC_NOTIFY_TYPE_WATCH:
211     /** WATCH */
212     silc_fsm_next(fsm, silc_client_notify_watch);
213     break;
214
215   default:
216     /** Unknown notify */
217     silc_notify_payload_free(payload);
218     silc_packet_free(packet);
219     silc_free(notify);
220     return SILC_FSM_FINISH;
221     break;
222   }
223
224   return SILC_FSM_CONTINUE;
225 }
226
227 /* Notify processed, finish the packet processing thread */
228
229 SILC_FSM_STATE(silc_client_notify_processed)
230 {
231   SilcClientNotify notify = state_context;
232   SilcPacket packet = notify->packet;
233   SilcNotifyPayload payload = notify->payload;
234
235   silc_notify_payload_free(payload);
236   silc_packet_free(packet);
237   silc_free(notify);
238   return SILC_FSM_FINISH;
239 }
240
241 /********************************** NONE ************************************/
242
243 SILC_FSM_STATE(silc_client_notify_none)
244 {
245   SilcClientConnection conn = fsm_context;
246   SilcClient client = conn->client;
247   SilcClientNotify notify = state_context;
248   SilcNotifyPayload payload = notify->payload;
249   SilcNotifyType type = silc_notify_get_type(payload);
250   SilcArgumentPayload args = silc_notify_get_args(payload);
251
252   SILC_LOG_DEBUG(("Notify: NONE"));
253
254   /* Notify application */
255   NOTIFY(client, conn, type, silc_argument_get_arg_type(args, 1, NULL));
256
257   /** Notify processed */
258   silc_fsm_next(fsm, silc_client_notify_processed);
259   return SILC_FSM_CONTINUE;
260 }
261
262 /********************************* INVITE ***********************************/
263
264 /* Someone invite me to a channel */
265
266 SILC_FSM_STATE(silc_client_notify_invite)
267 {
268   SilcClientConnection conn = fsm_context;
269   SilcClient client = conn->client;
270   SilcClientNotify notify = state_context;
271   SilcNotifyPayload payload = notify->payload;
272   SilcNotifyType type = silc_notify_get_type(payload);
273   SilcArgumentPayload args = silc_notify_get_args(payload);
274   SilcClientEntry client_entry;
275   SilcChannelEntry channel = NULL;
276   unsigned char *tmp;
277   SilcUInt32 tmp_len;
278   SilcID id;
279
280   SILC_LOG_DEBUG(("Notify: INVITE"));
281
282   /* Get Channel ID */
283   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
284     goto out;
285
286   /* Get the channel name */
287   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
288   if (!tmp)
289     goto out;
290
291   /* Get the channel entry */
292   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
293   if (!channel)
294     goto out;
295
296   /* If channel is being resolved handle notify after resolving */
297   if (channel->internal.resolve_cmd_ident) {
298     silc_client_unref_channel(client, conn, channel);
299     SILC_FSM_CALL(silc_client_command_pending(
300                                       conn, SILC_COMMAND_NONE,
301                                       channel->internal.resolve_cmd_ident,
302                                       silc_client_notify_wait_continue,
303                                       notify));
304     /* NOT REACHED */
305   }
306
307   /* Get sender Client ID */
308   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
309     goto out;
310
311   /* Find Client entry and if not found query it */
312   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
313   if (!client_entry || !client_entry->internal.valid) {
314     /** Resolve client */
315     silc_client_unref_client(client, conn, client_entry);
316     notify->channel = channel;
317     SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
318                   silc_client_get_client_by_id_resolve(
319                                          client, conn, &id.u.client_id, NULL,
320                                          silc_client_notify_resolved,
321                                          notify));
322     /* NOT REACHED */
323   }
324
325   /* Notify application */
326   NOTIFY(client, conn, type, channel, tmp, client_entry);
327
328   silc_client_unref_client(client, conn, client_entry);
329
330  out:
331   /** Notify processed */
332   silc_client_unref_channel(client, conn, channel);
333   silc_fsm_next(fsm, silc_client_notify_processed);
334   return SILC_FSM_CONTINUE;
335 }
336
337 /********************************** JOIN ************************************/
338
339 /* Someone joined a channel */
340
341 SILC_FSM_STATE(silc_client_notify_join)
342 {
343   SilcClientConnection conn = fsm_context;
344   SilcClient client = conn->client;
345   SilcClientNotify notify = state_context;
346   SilcNotifyPayload payload = notify->payload;
347   SilcNotifyType type = silc_notify_get_type(payload);
348   SilcArgumentPayload args = silc_notify_get_args(payload);
349   SilcClientEntry client_entry;
350   SilcChannelEntry channel = NULL;
351   SilcID id;
352
353   SILC_LOG_DEBUG(("Notify: JOIN"));
354
355   /* Get Channel ID */
356   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
357     goto out;
358
359   /* Get channel entry */
360   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
361   if (!channel)
362     goto out;
363
364   /* If channel is being resolved handle notify after resolving */
365   if (channel->internal.resolve_cmd_ident) {
366     silc_client_unref_channel(client, conn, channel);
367     SILC_FSM_CALL(silc_client_command_pending(
368                                       conn, SILC_COMMAND_NONE,
369                                       channel->internal.resolve_cmd_ident,
370                                       silc_client_notify_wait_continue,
371                                       notify));
372     /* NOT REACHED */
373   }
374
375   /* Get Client ID */
376   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
377     goto out;
378
379   /* Find client entry and if not found query it.  If we just queried it
380      don't do it again, unless some data (like username) is missing. */
381   client_entry = notify->client_entry;
382   if (!client_entry)
383     client_entry = silc_client_get_client(client, conn, &id.u.client_id);
384   if (!client_entry || !client_entry->internal.valid ||
385       !client_entry->username[0]) {
386     /** Resolve client */
387     notify->channel = channel;
388     notify->client_entry = client_entry;
389     SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
390                   silc_client_get_client_by_id_resolve(
391                                          client, conn, client_entry ?
392                                          &client_entry->id : &id.u.client_id,
393                                          NULL, silc_client_notify_resolved,
394                                          notify));
395     /* NOT REACHED */
396   }
397
398   silc_rwlock_wrlock(client_entry->internal.lock);
399   silc_rwlock_wrlock(channel->internal.lock);
400
401   if (client_entry != conn->local_entry)
402     silc_client_nickname_format(client, conn, client_entry, FALSE);
403
404   /* Join the client to channel */
405   if (!silc_client_add_to_channel(client, conn, channel, client_entry, 0)) {
406     silc_rwlock_unlock(channel->internal.lock);
407     silc_rwlock_unlock(client_entry->internal.lock);
408     goto out;
409   }
410
411   silc_rwlock_unlock(channel->internal.lock);
412   silc_rwlock_unlock(client_entry->internal.lock);
413
414   /* Notify application. */
415   NOTIFY(client, conn, type, client_entry, channel);
416
417   silc_client_unref_client(client, conn, client_entry);
418
419  out:
420   /** Notify processed */
421   silc_client_unref_channel(client, conn, channel);
422   silc_fsm_next(fsm, silc_client_notify_processed);
423   return SILC_FSM_CONTINUE;
424 }
425
426 /********************************** LEAVE ***********************************/
427
428 /* Someone left a channel */
429
430 SILC_FSM_STATE(silc_client_notify_leave)
431 {
432   SilcClientConnection conn = fsm_context;
433   SilcClient client = conn->client;
434   SilcClientNotify notify = state_context;
435   SilcNotifyPayload payload = notify->payload;
436   SilcPacket packet = notify->packet;
437   SilcNotifyType type = silc_notify_get_type(payload);
438   SilcArgumentPayload args = silc_notify_get_args(payload);
439   SilcClientEntry client_entry = NULL;
440   SilcChannelEntry channel = NULL;
441   SilcID id;
442
443   SILC_LOG_DEBUG(("Notify: LEAVE"));
444
445   /* Get channel entry */
446   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
447                       &id.u.channel_id, sizeof(id.u.channel_id)))
448     goto out;
449   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
450   if (!channel)
451     goto out;
452
453   /* If channel is being resolved handle notify after resolving */
454   if (channel->internal.resolve_cmd_ident) {
455     silc_client_unref_channel(client, conn, channel);
456     SILC_FSM_CALL(silc_client_command_pending(
457                                       conn, SILC_COMMAND_NONE,
458                                       channel->internal.resolve_cmd_ident,
459                                       silc_client_notify_wait_continue,
460                                       notify));
461     /* NOT REACHED */
462   }
463
464   /* Get Client ID */
465   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
466     goto out;
467
468   /* Find Client entry */
469   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
470   if (!client_entry)
471     goto out;
472
473   /* Remove client from channel */
474   if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
475     goto out;
476
477   /* Notify application. */
478   NOTIFY(client, conn, type, client_entry, channel);
479
480   silc_client_unref_client(client, conn, client_entry);
481
482  out:
483   /** Notify processed */
484   silc_client_unref_channel(client, conn, channel);
485   silc_fsm_next(fsm, silc_client_notify_processed);
486   return SILC_FSM_CONTINUE;
487 }
488
489 /********************************* SIGNOFF **********************************/
490
491 /* Someone quit SILC network */
492
493 SILC_FSM_STATE(silc_client_notify_signoff)
494 {
495   SilcClientConnection conn = fsm_context;
496   SilcClient client = conn->client;
497   SilcClientNotify notify = state_context;
498   SilcNotifyPayload payload = notify->payload;
499   SilcPacket packet = notify->packet;
500   SilcNotifyType type = silc_notify_get_type(payload);
501   SilcArgumentPayload args = silc_notify_get_args(payload);
502   SilcClientEntry client_entry;
503   SilcChannelEntry channel;
504   unsigned char *tmp;
505   SilcUInt32 tmp_len;
506   SilcID id;
507
508   SILC_LOG_DEBUG(("Notify: SIGNOFF"));
509
510   /* Get Client ID */
511   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
512     goto out;
513
514   /* Find Client entry */
515   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
516   if (!client_entry)
517     goto out;
518
519   /* Get signoff message */
520   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
521   if (tmp && tmp_len > 128)
522     tmp[128] = '\0';
523
524   /* Notify application */
525   if (client_entry->internal.valid)
526     NOTIFY(client, conn, type, client_entry, tmp);
527
528   /* Remove from channel */
529   if (packet->dst_id_type == SILC_ID_CHANNEL) {
530     if (silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
531                        &id.u.channel_id, sizeof(id.u.channel_id))) {
532       channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
533       if (channel) {
534         silc_client_remove_from_channel(client, conn, channel, client_entry);
535         silc_client_unref_channel(client, conn, channel);
536       }
537     }
538   }
539
540   /* Delete client */
541   client_entry->internal.valid = FALSE;
542   silc_client_del_client(client, conn, client_entry);
543   silc_client_unref_client(client, conn, client_entry);
544
545  out:
546   /** Notify processed */
547   silc_fsm_next(fsm, silc_client_notify_processed);
548   return SILC_FSM_CONTINUE;
549 }
550
551 /******************************** TOPIC_SET *********************************/
552
553 /* Someone set topic on a channel */
554
555 SILC_FSM_STATE(silc_client_notify_topic_set)
556 {
557   SilcClientConnection conn = fsm_context;
558   SilcClient client = conn->client;
559   SilcClientNotify notify = state_context;
560   SilcNotifyPayload payload = notify->payload;
561   SilcPacket packet = notify->packet;
562   SilcNotifyType type = silc_notify_get_type(payload);
563   SilcArgumentPayload args = silc_notify_get_args(payload);
564   SilcClientEntry client_entry = NULL;
565   SilcChannelEntry channel = NULL, channel_entry = NULL;
566   SilcServerEntry server = NULL;
567   void *entry;
568   unsigned char *tmp;
569   SilcUInt32 tmp_len;
570   SilcID id;
571
572   SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
573
574   /* Get channel entry */
575   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
576                       &id.u.channel_id, sizeof(id.u.channel_id)))
577     goto out;
578   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
579   if (!channel)
580     goto out;
581
582   /* If channel is being resolved handle notify after resolving */
583   if (channel->internal.resolve_cmd_ident) {
584     silc_client_unref_channel(client, conn, channel);
585     SILC_FSM_CALL(silc_client_command_pending(
586                                       conn, SILC_COMMAND_NONE,
587                                       channel->internal.resolve_cmd_ident,
588                                       silc_client_notify_wait_continue,
589                                       notify));
590     /* NOT REACHED */
591   }
592
593   /* Get ID of topic changer */
594   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
595     goto out;
596
597   /* Get topic */
598   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
599   if (!tmp)
600     goto out;
601
602   if (id.type == SILC_ID_CLIENT) {
603     /* Find Client entry */
604     client_entry = notify->client_entry;
605     if (!client_entry) {
606       client_entry = silc_client_get_client(client, conn, &id.u.client_id);
607       if (!client_entry || !client_entry->internal.valid) {
608         /** Resolve client */
609         notify->channel = channel;
610         notify->client_entry = client_entry;
611         SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
612                       silc_client_get_client_by_id_resolve(
613                                            client, conn, &id.u.client_id, NULL,
614                                            silc_client_notify_resolved,
615                                            notify));
616         /* NOT REACHED */
617       }
618     }
619
620     /* If client is not on channel, ignore this notify */
621     if (!silc_client_on_channel(channel, client_entry))
622       goto out;
623
624     entry = client_entry;
625   } else if (id.type == SILC_ID_SERVER) {
626     /* Find Server entry */
627     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
628     if (!server) {
629       /** Resolve server */
630       notify->channel = channel;
631       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
632                     silc_client_get_server_by_id_resolve(
633                                            client, conn, &id.u.server_id,
634                                            silc_client_notify_resolved,
635                                            notify));
636       /* NOT REACHED */
637     }
638     entry = server;
639   } else {
640     /* Find Channel entry */
641     channel_entry = silc_client_get_channel_by_id(client, conn,
642                                                   &id.u.channel_id);
643     if (!channel_entry) {
644       /** Resolve channel */
645       notify->channel = channel;
646       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
647                     silc_client_get_channel_by_id_resolve(
648                                     client, conn, &id.u.channel_id,
649                                     silc_client_notify_resolved,
650                                     notify));
651       /* NOT REACHED */
652     }
653     entry = channel_entry;
654   }
655
656   silc_rwlock_wrlock(channel->internal.lock);
657   silc_free(channel->topic);
658   channel->topic = silc_memdup(tmp, strlen(tmp));
659   silc_rwlock_unlock(channel->internal.lock);
660
661   /* Notify application. */
662   NOTIFY(client, conn, type, id.type, entry, channel->topic, channel);
663
664   if (client_entry)
665     silc_client_unref_client(client, conn, client_entry);
666   if (server)
667     silc_client_unref_server(client, conn, server);
668   if (channel_entry)
669     silc_client_unref_channel(client, conn, channel_entry);
670
671  out:
672   /** Notify processed */
673   silc_client_unref_channel(client, conn, channel);
674   silc_fsm_next(fsm, silc_client_notify_processed);
675   return SILC_FSM_CONTINUE;
676 }
677
678 /****************************** NICK_CHANGE *********************************/
679
680 /* Someone changed their nickname on a channel */
681
682 SILC_FSM_STATE(silc_client_notify_nick_change)
683 {
684   SilcClientConnection conn = fsm_context;
685   SilcClient client = conn->client;
686   SilcClientNotify notify = state_context;
687   SilcNotifyPayload payload = notify->payload;
688   SilcNotifyType type = silc_notify_get_type(payload);
689   SilcArgumentPayload args = silc_notify_get_args(payload);
690   SilcClientEntry client_entry = NULL;
691   unsigned char *tmp, oldnick[128 + 1];
692   SilcUInt32 tmp_len;
693   SilcID id, id2;
694   SilcBool valid;
695
696   SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
697
698   /* Get ID */
699   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
700     goto out;
701
702   /* Ignore my ID */
703   if (conn->local_id &&
704       SILC_ID_CLIENT_COMPARE(&id.u.client_id, conn->local_id))
705     goto out;
706
707   /* Get new Client ID */
708   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id2, NULL))
709     goto out;
710
711   /* Ignore my ID */
712   if (conn->local_id &&
713       SILC_ID_CLIENT_COMPARE(&id2.u.client_id, conn->local_id))
714     goto out;
715
716   /* Find old client entry.  If we don't have the entry, we ignore this
717      notify. */
718   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
719   if (!client_entry)
720     goto out;
721   valid = client_entry->internal.valid;
722
723   /* Take the new nickname */
724   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
725   if (!tmp)
726     goto out;
727
728   silc_rwlock_wrlock(client_entry->internal.lock);
729
730   /* Check whether nickname changed at all.  It is possible that nick
731      change notify is received but nickname didn't change, only the
732      ID changes.  If Client ID hash match, nickname didn't change. */
733   if (SILC_ID_COMPARE_HASH(&client_entry->id, &id2.u.client_id) &&
734       silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
735     /* Nickname didn't change.  Update only Client ID.  We don't notify
736        application because nickname didn't change. */
737     silc_mutex_lock(conn->internal->lock);
738     silc_idcache_update_by_context(conn->internal->client_cache, client_entry,
739                                    &id2.u.client_id, NULL, FALSE);
740     silc_mutex_unlock(conn->internal->lock);
741     silc_rwlock_unlock(client_entry->internal.lock);
742     goto out;
743   }
744
745   /* Change the nickname */
746   memcpy(oldnick, client_entry->nickname, sizeof(client_entry->nickname));
747   if (!silc_client_change_nickname(client, conn, client_entry, tmp,
748                                    &id2.u.client_id, NULL, 0)) {
749     silc_rwlock_unlock(client_entry->internal.lock);
750     goto out;
751   }
752
753   silc_rwlock_unlock(client_entry->internal.lock);
754
755   /* Notify application, if client entry is valid.  We do not send nick change
756      notify for entries that were invalid (application doesn't know them). */
757   if (valid)
758     NOTIFY(client, conn, type, client_entry, oldnick, client_entry->nickname);
759
760  out:
761   /** Notify processed */
762   silc_client_unref_client(client, conn, client_entry);
763   silc_fsm_next(fsm, silc_client_notify_processed);
764   return SILC_FSM_CONTINUE;
765 }
766
767 /****************************** CMODE_CHANGE ********************************/
768
769 /* Someone changed channel mode */
770
771 SILC_FSM_STATE(silc_client_notify_cmode_change)
772 {
773   SilcClientConnection conn = fsm_context;
774   SilcClient client = conn->client;
775   SilcClientNotify notify = state_context;
776   SilcNotifyPayload payload = notify->payload;
777   SilcPacket packet = notify->packet;
778   SilcNotifyType type = silc_notify_get_type(payload);
779   SilcArgumentPayload args = silc_notify_get_args(payload);
780   SilcClientEntry client_entry = NULL;
781   SilcChannelEntry channel = NULL, channel_entry = NULL;
782   SilcServerEntry server = NULL;
783   void *entry;
784   unsigned char *tmp;
785   SilcUInt32 tmp_len, mode;
786   SilcID id;
787   char *passphrase, *cipher, *hmac;
788   SilcPublicKey founder_key = NULL;
789   SilcDList chpks = NULL;
790
791   SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
792
793   /* Get channel entry */
794   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
795                       &id.u.channel_id, sizeof(id.u.channel_id)))
796     goto out;
797   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
798   if (!channel)
799     goto out;
800
801   /* If channel is being resolved handle notify after resolving */
802   if (channel->internal.resolve_cmd_ident) {
803     silc_client_unref_channel(client, conn, channel);
804     SILC_FSM_CALL(silc_client_command_pending(
805                                       conn, SILC_COMMAND_NONE,
806                                       channel->internal.resolve_cmd_ident,
807                                       silc_client_notify_wait_continue,
808                                       notify));
809     /* NOT REACHED */
810   }
811
812   /* Get the mode */
813   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
814   if (!tmp)
815     goto out;
816   SILC_GET32_MSB(mode, tmp);
817
818   /* Get ID of who changed the mode */
819   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
820     goto out;
821
822   if (id.type == SILC_ID_CLIENT) {
823     /* Find Client entry */
824     client_entry = notify->client_entry;
825     if (!client_entry) {
826       client_entry = silc_client_get_client(client, conn, &id.u.client_id);
827       if (!client_entry || !client_entry->internal.valid) {
828         /** Resolve client */
829         notify->channel = channel;
830         notify->client_entry = client_entry;
831         SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
832                       silc_client_get_client_by_id_resolve(
833                                            client, conn, &id.u.client_id, NULL,
834                                            silc_client_notify_resolved,
835                                            notify));
836         /* NOT REACHED */
837       }
838     }
839
840     /* If client is not on channel, ignore this notify */
841     if (!silc_client_on_channel(channel, client_entry))
842       goto out;
843
844     entry = client_entry;
845   } else if (id.type == SILC_ID_SERVER) {
846     /* Find Server entry */
847     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
848     if (!server) {
849       /** Resolve server */
850       notify->channel = channel;
851       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
852                     silc_client_get_server_by_id_resolve(
853                                            client, conn, &id.u.server_id,
854                                            silc_client_notify_resolved,
855                                            notify));
856       /* NOT REACHED */
857     }
858     entry = server;
859   } else {
860     /* Find Channel entry */
861     channel_entry = silc_client_get_channel_by_id(client, conn,
862                                                   &id.u.channel_id);
863     if (!channel_entry) {
864       /** Resolve channel */
865       notify->channel = channel;
866       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
867                     silc_client_get_channel_by_id_resolve(
868                                     client, conn, &id.u.channel_id,
869                                     silc_client_notify_resolved,
870                                     notify));
871       /* NOT REACHED */
872     }
873     entry = channel_entry;
874   }
875
876   silc_rwlock_wrlock(channel->internal.lock);
877
878   /* Get the channel founder key if it was set */
879   tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
880   if (tmp) {
881     if (!silc_public_key_payload_decode(tmp, tmp_len, &founder_key)) {
882       silc_rwlock_unlock(channel->internal.lock);
883       goto out;
884     }
885     if (!channel->founder_key) {
886       channel->founder_key = founder_key;
887       founder_key = NULL;
888     }
889   }
890
891   /* Get the cipher */
892   cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
893
894   /* Get the hmac */
895   hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
896   if (hmac) {
897     unsigned char hash[SILC_HASH_MAXLEN];
898     SilcHmac newhmac;
899
900     if (!silc_hmac_alloc(hmac, NULL, &newhmac)) {
901       silc_rwlock_unlock(channel->internal.lock);
902       goto out;
903     }
904
905     /* Get HMAC key from the old HMAC context, and update it to the new one */
906     tmp = (unsigned char *)silc_hmac_get_key(channel->internal.hmac, &tmp_len);
907     if (tmp) {
908       silc_hash_make(silc_hmac_get_hash(newhmac), tmp, tmp_len, hash);
909       silc_hmac_set_key(newhmac, hash,
910                         silc_hash_len(silc_hmac_get_hash(newhmac)));
911       if (channel->internal.hmac)
912         silc_hmac_free(channel->internal.hmac);
913       channel->internal.hmac = newhmac;
914       memset(hash, 0, sizeof(hash));
915     }
916   }
917
918   /* Get the passphrase if it was set */
919   passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
920
921   /* Get user limit */
922   tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
923   if (tmp && tmp_len == 4)
924     SILC_GET32_MSB(channel->user_limit, tmp);
925   if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
926     channel->user_limit = 0;
927
928   /* Save the new mode */
929   channel->mode = mode;
930
931   /* Get the channel public key that was added or removed */
932   tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
933   if (tmp)
934     silc_client_channel_save_public_keys(channel, tmp, tmp_len);
935
936   silc_rwlock_unlock(channel->internal.lock);
937
938   /* Notify application. */
939   NOTIFY(client, conn, type, id.type, entry, mode, cipher, hmac,
940          passphrase, channel->founder_key, chpks, channel);
941
942  out:
943   if (founder_key)
944     silc_pkcs_public_key_free(founder_key);
945   if (chpks)
946     silc_argument_list_free(chpks, SILC_ARGUMENT_PUBLIC_KEY);
947   if (client_entry)
948     silc_client_unref_client(client, conn, client_entry);
949   if (server)
950     silc_client_unref_server(client, conn, server);
951   if (channel_entry)
952     silc_client_unref_channel(client, conn, channel_entry);
953   silc_client_unref_channel(client, conn, channel);
954
955   /** Notify processed */
956   silc_fsm_next(fsm, silc_client_notify_processed);
957   return SILC_FSM_CONTINUE;
958 }
959
960 /***************************** CUMODE_CHANGE ********************************/
961
962 /* Someone changed a user's mode on a channel */
963
964 SILC_FSM_STATE(silc_client_notify_cumode_change)
965 {
966   SilcClientConnection conn = fsm_context;
967   SilcClient client = conn->client;
968   SilcClientNotify notify = state_context;
969   SilcNotifyPayload payload = notify->payload;
970   SilcPacket packet = notify->packet;
971   SilcNotifyType type = silc_notify_get_type(payload);
972   SilcArgumentPayload args = silc_notify_get_args(payload);
973   SilcClientEntry client_entry = NULL, client_entry2 = NULL;
974   SilcChannelEntry channel = NULL, channel_entry = NULL;
975   SilcServerEntry server = NULL;
976   SilcChannelUser chu;
977   void *entry;
978   unsigned char *tmp;
979   SilcUInt32 tmp_len, mode;
980   SilcID id, id2;
981
982   SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
983
984   /* Get channel entry */
985   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
986                       &id.u.channel_id, sizeof(id.u.channel_id)))
987     goto out;
988   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
989   if (!channel)
990     goto out;
991
992   /* If channel is being resolved handle notify after resolving */
993   if (channel->internal.resolve_cmd_ident) {
994     silc_client_unref_channel(client, conn, channel);
995     SILC_FSM_CALL(silc_client_command_pending(
996                                       conn, SILC_COMMAND_NONE,
997                                       channel->internal.resolve_cmd_ident,
998                                       silc_client_notify_wait_continue,
999                                       notify));
1000     /* NOT REACHED */
1001   }
1002
1003   /* Get target Client ID */
1004   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id2, NULL))
1005     goto out;
1006
1007   /* Find target Client entry */
1008   client_entry2 = silc_client_get_client_by_id(client, conn, &id2.u.client_id);
1009   if (!client_entry2 || !client_entry2->internal.valid) {
1010     /** Resolve client */
1011     silc_client_unref_client(client, conn, client_entry2);
1012     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1013                                          client, conn, &id2.u.client_id, NULL,
1014                                          silc_client_notify_resolved,
1015                                          notify));
1016     /* NOT REACHED */
1017   }
1018
1019   /* If target client is not on channel, ignore this notify */
1020   if (!silc_client_on_channel(channel, client_entry2))
1021     goto out;
1022
1023   /* Get the mode */
1024   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1025   if (!tmp)
1026     goto out;
1027   SILC_GET32_MSB(mode, tmp);
1028
1029   /* Get ID of mode changer */
1030   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1031     goto out;
1032
1033   if (id.type == SILC_ID_CLIENT) {
1034     /* Find Client entry */
1035     client_entry = notify->client_entry;
1036     if (!client_entry) {
1037       client_entry = silc_client_get_client(client, conn, &id.u.client_id);
1038       if (!client_entry || !client_entry->internal.valid) {
1039         /** Resolve client */
1040         notify->channel = channel;
1041         notify->client_entry = client_entry;
1042         SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1043                       silc_client_get_client_by_id_resolve(
1044                                            client, conn, &id.u.client_id, NULL,
1045                                            silc_client_notify_resolved,
1046                                            notify));
1047         /* NOT REACHED */
1048       }
1049     }
1050
1051     /* If client is not on channel, ignore this notify */
1052     if (!silc_client_on_channel(channel, client_entry))
1053       goto out;
1054
1055     entry = client_entry;
1056   } else if (id.type == SILC_ID_SERVER) {
1057     /* Find Server entry */
1058     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1059     if (!server) {
1060       /** Resolve server */
1061       notify->channel = channel;
1062       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1063                     silc_client_get_server_by_id_resolve(
1064                                            client, conn, &id.u.server_id,
1065                                            silc_client_notify_resolved,
1066                                            notify));
1067       /* NOT REACHED */
1068     }
1069     entry = server;
1070   } else {
1071     /* Find Channel entry */
1072     channel_entry = silc_client_get_channel_by_id(client, conn,
1073                                                   &id.u.channel_id);
1074     if (!channel_entry) {
1075       /** Resolve channel */
1076       notify->channel = channel;
1077       SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1078                     silc_client_get_channel_by_id_resolve(
1079                                     client, conn, &id.u.channel_id,
1080                                     silc_client_notify_resolved,
1081                                     notify));
1082       /* NOT REACHED */
1083     }
1084     entry = channel_entry;
1085   }
1086
1087   /* Save the mode */
1088   silc_rwlock_wrlock(channel->internal.lock);
1089   chu = silc_client_on_channel(channel, client_entry2);
1090   if (chu)
1091     chu->mode = mode;
1092   silc_rwlock_unlock(channel->internal.lock);
1093
1094   /* Notify application. */
1095   NOTIFY(client, conn, type, id.type, entry, mode, client_entry2, channel);
1096
1097  out:
1098   silc_client_unref_client(client, conn, client_entry2);
1099   if (client_entry)
1100     silc_client_unref_client(client, conn, client_entry);
1101   if (server)
1102     silc_client_unref_server(client, conn, server);
1103   if (channel_entry)
1104     silc_client_unref_channel(client, conn, channel_entry);
1105   silc_client_unref_channel(client, conn, channel);
1106
1107   /** Notify processed */
1108   silc_fsm_next(fsm, silc_client_notify_processed);
1109   return SILC_FSM_CONTINUE;
1110 }
1111
1112 /********************************* MOTD *************************************/
1113
1114 /* Received Message of the day */
1115
1116 SILC_FSM_STATE(silc_client_notify_motd)
1117 {
1118   SilcClientConnection conn = fsm_context;
1119   SilcClient client = conn->client;
1120   SilcClientNotify notify = state_context;
1121   SilcNotifyPayload payload = notify->payload;
1122   SilcNotifyType type = silc_notify_get_type(payload);
1123   SilcArgumentPayload args = silc_notify_get_args(payload);
1124   unsigned char *tmp;
1125   SilcUInt32 tmp_len;
1126
1127   SILC_LOG_DEBUG(("Notify: MOTD"));
1128
1129   /* Get motd */
1130   tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1131   if (!tmp)
1132     goto out;
1133
1134   /* Notify application */
1135   NOTIFY(client, conn, type, tmp);
1136
1137  out:
1138   /** Notify processed */
1139   silc_fsm_next(fsm, silc_client_notify_processed);
1140   return SILC_FSM_CONTINUE;
1141 }
1142
1143 /**************************** CHANNEL CHANGE ********************************/
1144
1145 /* Router has enforced a new ID to a channel, change it */
1146
1147 SILC_FSM_STATE(silc_client_notify_channel_change)
1148 {
1149   SilcClientConnection conn = fsm_context;
1150   SilcClient client = conn->client;
1151   SilcClientNotify notify = state_context;
1152   SilcNotifyPayload payload = notify->payload;
1153   SilcNotifyType type = silc_notify_get_type(payload);
1154   SilcArgumentPayload args = silc_notify_get_args(payload);
1155   SilcChannelEntry channel = NULL;
1156   SilcID id;
1157
1158   SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1159
1160   /* Get the old ID */
1161   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1162     goto out;
1163
1164   /* Get the channel entry */
1165   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1166   if (!channel)
1167     goto out;
1168
1169   /* If channel is being resolved handle notify after resolving */
1170   if (channel->internal.resolve_cmd_ident) {
1171     silc_client_unref_channel(client, conn, channel);
1172     SILC_FSM_CALL(silc_client_command_pending(
1173                                       conn, SILC_COMMAND_NONE,
1174                                       channel->internal.resolve_cmd_ident,
1175                                       silc_client_notify_wait_continue,
1176                                       notify));
1177     /* NOT REACHED */
1178   }
1179
1180   /* Get the new ID */
1181   if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1182     goto out;
1183
1184   /* Replace the Channel ID */
1185   if (!silc_client_replace_channel_id(client, conn, channel, &id.u.channel_id))
1186     goto out;
1187
1188   /* Notify application */
1189   NOTIFY(client, conn, type, channel, channel);
1190
1191  out:
1192   /** Notify processed */
1193   silc_client_unref_channel(client, conn, channel);
1194   silc_fsm_next(fsm, silc_client_notify_processed);
1195   return SILC_FSM_CONTINUE;
1196 }
1197
1198 /******************************** KICKED ************************************/
1199
1200 /* Some client was kicked from a channel */
1201
1202 SILC_FSM_STATE(silc_client_notify_kicked)
1203 {
1204   SilcClientConnection conn = fsm_context;
1205   SilcClient client = conn->client;
1206   SilcClientNotify notify = state_context;
1207   SilcNotifyPayload payload = notify->payload;
1208   SilcPacket packet = notify->packet;
1209   SilcNotifyType type = silc_notify_get_type(payload);
1210   SilcArgumentPayload args = silc_notify_get_args(payload);
1211   SilcClientEntry client_entry, client_entry2;
1212   SilcChannelEntry channel = NULL;
1213   unsigned char *tmp;
1214   SilcUInt32 tmp_len;
1215   SilcID id;
1216
1217   SILC_LOG_DEBUG(("Notify: KICKED"));
1218
1219   /* Get channel entry */
1220   if (!silc_id_str2id(packet->dst_id, packet->dst_id_len, SILC_ID_CHANNEL,
1221                       &id.u.channel_id, sizeof(id.u.channel_id)))
1222     goto out;
1223   channel = silc_client_get_channel_by_id(client, conn, &id.u.channel_id);
1224   if (!channel)
1225     goto out;
1226
1227   /* If channel is being resolved handle notify after resolving */
1228   if (channel->internal.resolve_cmd_ident) {
1229     silc_client_unref_channel(client, conn, channel);
1230     SILC_FSM_CALL(silc_client_command_pending(
1231                                       conn, SILC_COMMAND_NONE,
1232                                       channel->internal.resolve_cmd_ident,
1233                                       silc_client_notify_wait_continue,
1234                                       notify));
1235     /* NOT REACHED */
1236   }
1237
1238   /* Get the kicked Client ID */
1239   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1240     goto out;
1241
1242   /* Find client entry */
1243   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1244   if (!client_entry)
1245     goto out;
1246
1247   /* Get kicker's Client ID */
1248   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1249     goto out;
1250
1251   /* Find kicker's client entry and if not found resolve it */
1252   client_entry2 = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1253   if (!client_entry2 || !client_entry2->internal.valid) {
1254     /** Resolve client */
1255     silc_client_unref_client(client, conn, client_entry);
1256     silc_client_unref_client(client, conn, client_entry2);
1257     notify->channel = channel;
1258     SILC_FSM_CALL(channel->internal.resolve_cmd_ident =
1259                   silc_client_get_client_by_id_resolve(
1260                                          client, conn, &id.u.client_id, NULL,
1261                                          silc_client_notify_resolved,
1262                                          notify));
1263     /* NOT REACHED */
1264   }
1265
1266   /* Get comment */
1267   tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1268
1269   /* Remove kicked client from channel */
1270   if (client_entry != conn->local_entry) {
1271     if (!silc_client_remove_from_channel(client, conn, channel, client_entry))
1272       goto out;
1273   }
1274
1275   /* Notify application. */
1276   NOTIFY(client, conn, type, client_entry, tmp, client_entry2, channel);
1277
1278   /* If I was kicked from channel, remove the channel */
1279   if (client_entry == conn->local_entry) {
1280     if (conn->current_channel == channel)
1281       conn->current_channel = NULL;
1282     silc_client_empty_channel(client, conn, channel);
1283     silc_client_del_channel(client, conn, channel);
1284   }
1285
1286   silc_client_unref_client(client, conn, client_entry);
1287   silc_client_unref_client(client, conn, client_entry2);
1288
1289  out:
1290   /** Notify processed */
1291   silc_client_unref_channel(client, conn, channel);
1292   silc_fsm_next(fsm, silc_client_notify_processed);
1293   return SILC_FSM_CONTINUE;
1294 }
1295
1296 /******************************** KILLED ************************************/
1297
1298 /* Some client was killed from the network */
1299
1300 SILC_FSM_STATE(silc_client_notify_killed)
1301 {
1302   SilcClientConnection conn = fsm_context;
1303   SilcClient client = conn->client;
1304   SilcClientNotify notify = state_context;
1305   SilcNotifyPayload payload = notify->payload;
1306   SilcNotifyType type = silc_notify_get_type(payload);
1307   SilcArgumentPayload args = silc_notify_get_args(payload);
1308   SilcClientEntry client_entry = NULL, client_entry2 = NULL;
1309   SilcChannelEntry channel_entry = NULL;
1310   SilcServerEntry server = NULL;
1311   void *entry;
1312   char *comment;
1313   SilcUInt32 comment_len;
1314   SilcID id;
1315
1316   SILC_LOG_DEBUG(("Notify: KILLED"));
1317
1318   /* Get Client ID */
1319   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1320     goto out;
1321
1322   /* Find Client entry */
1323   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1324   if (!client_entry)
1325     goto out;
1326
1327   /* Get comment */
1328   comment = silc_argument_get_arg_type(args, 2, &comment_len);
1329
1330   /* Get killer's ID */
1331   if (!silc_argument_get_decoded(args, 3, SILC_ARGUMENT_ID, &id, NULL))
1332     goto out;
1333
1334   if (id.type == SILC_ID_CLIENT) {
1335     /* Find Client entry */
1336     client_entry2 = silc_client_get_client_by_id(client, conn,
1337                                                  &id.u.client_id);
1338     if (!client_entry2 || !client_entry2->internal.valid) {
1339       /** Resolve client */
1340       silc_client_unref_client(client, conn, client_entry);
1341       silc_client_unref_client(client, conn, client_entry2);
1342       SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1343                                            client, conn, &id.u.client_id, NULL,
1344                                            silc_client_notify_resolved,
1345                                            notify));
1346       /* NOT REACHED */
1347     }
1348     entry = client_entry2;
1349   } else if (id.type == SILC_ID_SERVER) {
1350     /* Find Server entry */
1351     server = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1352     if (!server) {
1353       /** Resolve server */
1354       SILC_FSM_CALL(silc_client_get_server_by_id_resolve(
1355                                            client, conn, &id.u.server_id,
1356                                            silc_client_notify_resolved,
1357                                            notify));
1358       /* NOT REACHED */
1359     }
1360     entry = server;
1361   } else {
1362     /* Find Channel entry */
1363     channel_entry = silc_client_get_channel_by_id(client, conn,
1364                                                   &id.u.channel_id);
1365     if (!channel_entry) {
1366       /** Resolve channel */
1367       SILC_FSM_CALL(silc_client_get_channel_by_id_resolve(
1368                                     client, conn, &id.u.channel_id,
1369                                     silc_client_notify_resolved,
1370                                     notify));
1371       /* NOT REACHED */
1372     }
1373     entry = channel_entry;
1374   }
1375
1376   /* Notify application. */
1377   NOTIFY(client, conn, type, client_entry, comment, id.type, entry);
1378
1379   /* Delete the killed client */
1380   if (client_entry != conn->local_entry) {
1381     silc_client_remove_from_channels(client, conn, client_entry);
1382     client_entry->internal.valid = FALSE;
1383     silc_client_del_client(client, conn, client_entry);
1384   }
1385
1386  out:
1387   silc_client_unref_client(client, conn, client_entry);
1388   if (client_entry2)
1389     silc_client_unref_client(client, conn, client_entry2);
1390   if (server)
1391     silc_client_unref_server(client, conn, server);
1392   if (channel_entry)
1393     silc_client_unref_channel(client, conn, channel_entry);
1394
1395   /** Notify processed */
1396   silc_fsm_next(fsm, silc_client_notify_processed);
1397   return SILC_FSM_CONTINUE;
1398 }
1399
1400 /**************************** SERVER SIGNOFF ********************************/
1401
1402 /* Some server quit SILC network.  Remove its clients from channels. */
1403
1404 SILC_FSM_STATE(silc_client_notify_server_signoff)
1405 {
1406   SilcClientConnection conn = fsm_context;
1407   SilcClient client = conn->client;
1408   SilcClientNotify notify = state_context;
1409   SilcNotifyPayload payload = notify->payload;
1410   SilcNotifyType type = silc_notify_get_type(payload);
1411   SilcArgumentPayload args = silc_notify_get_args(payload);
1412   SilcClientEntry client_entry;
1413   SilcServerEntry server_entry = NULL;
1414   SilcDList clients;
1415   SilcID id;
1416   int i;
1417
1418   SILC_LOG_DEBUG(("Notify: SERVER_SIGNOFF"));
1419
1420   clients = silc_dlist_init();
1421   if (!clients)
1422     goto out;
1423
1424   /* Get server ID */
1425   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1426     goto out;
1427
1428   /* Get server, in case we have it cached */
1429   server_entry = silc_client_get_server_by_id(client, conn, &id.u.server_id);
1430
1431   for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1432     /* Get Client ID */
1433     if (!silc_argument_get_decoded(args, i + 1, SILC_ARGUMENT_ID, &id, NULL))
1434       goto out;
1435
1436     /* Get the client entry */
1437     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1438     if (client_entry && client_entry->internal.valid)
1439       silc_dlist_add(clients, client_entry);
1440   }
1441
1442   /* Notify application. */
1443   NOTIFY(client, conn, type, server_entry, clients);
1444
1445   /* Delete the clients */
1446   silc_dlist_start(clients);
1447   while ((client_entry = silc_dlist_get(clients))) {
1448     silc_client_remove_from_channels(client, conn, client_entry);
1449     client_entry->internal.valid = FALSE;
1450     silc_client_del_client(client, conn, client_entry);
1451   }
1452
1453  out:
1454   /** Notify processed */
1455   silc_client_unref_server(client, conn, server_entry);
1456   silc_client_list_free(client, conn, clients);
1457   silc_fsm_next(fsm, silc_client_notify_processed);
1458   return SILC_FSM_CONTINUE;
1459 }
1460
1461 /******************************** ERROR *************************************/
1462
1463 /* Some error occurred */
1464
1465 SILC_FSM_STATE(silc_client_notify_error)
1466 {
1467   SilcClientConnection conn = fsm_context;
1468   SilcClient client = conn->client;
1469   SilcClientNotify notify = state_context;
1470   SilcNotifyPayload payload = notify->payload;
1471   SilcNotifyType type = silc_notify_get_type(payload);
1472   SilcArgumentPayload args = silc_notify_get_args(payload);
1473   SilcClientEntry client_entry;
1474   unsigned char *tmp;
1475   SilcUInt32 tmp_len;
1476   SilcID id;
1477   SilcStatus error;
1478
1479   /* Get error */
1480   tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1481   if (!tmp && tmp_len != 1)
1482     goto out;
1483   error = (SilcStatus)tmp[0];
1484
1485   SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1486
1487   /* Handle the error */
1488   if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1489     if (!silc_argument_get_decoded(args, 2, SILC_ARGUMENT_ID, &id, NULL))
1490       goto out;
1491     client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1492     if (client_entry) {
1493       silc_client_remove_from_channels(client, conn, client_entry);
1494       silc_client_del_client(client, conn, client_entry);
1495       silc_client_unref_client(client, conn, client_entry);
1496     }
1497   }
1498
1499   /* Notify application. */
1500   NOTIFY(client, conn, type, error);
1501
1502  out:
1503   /** Notify processed */
1504   silc_fsm_next(fsm, silc_client_notify_processed);
1505   return SILC_FSM_CONTINUE;
1506 }
1507
1508 /******************************** WATCH *************************************/
1509
1510 /* Received notify about some client we are watching */
1511
1512 SILC_FSM_STATE(silc_client_notify_watch)
1513 {
1514   SilcClientConnection conn = fsm_context;
1515   SilcClient client = conn->client;
1516   SilcClientNotify notify = state_context;
1517   SilcNotifyPayload payload = notify->payload;
1518   SilcNotifyType type = silc_notify_get_type(payload);
1519   SilcArgumentPayload args = silc_notify_get_args(payload);
1520   SilcClientEntry client_entry = NULL;
1521   SilcNotifyType ntype = 0;
1522   SilcBool del_client = FALSE;
1523   unsigned char *pk, *tmp;
1524   SilcUInt32 mode, pk_len, tmp_len;
1525   SilcPublicKey public_key = NULL;
1526   SilcID id;
1527
1528   SILC_LOG_DEBUG(("Notify: WATCH"));
1529
1530   /* Get sender Client ID */
1531   if (!silc_argument_get_decoded(args, 1, SILC_ARGUMENT_ID, &id, NULL))
1532     goto out;
1533
1534   /* Find client entry and if not found resolve it */
1535   client_entry = silc_client_get_client_by_id(client, conn, &id.u.client_id);
1536   if (!client_entry || !client_entry->internal.valid) {
1537     /** Resolve client */
1538     silc_client_unref_client(client, conn, client_entry);
1539     SILC_FSM_CALL(silc_client_get_client_by_id_resolve(
1540                                          client, conn, &id.u.client_id, NULL,
1541                                          silc_client_notify_resolved,
1542                                          notify));
1543     /* NOT REACHED */
1544   }
1545
1546   /* Get user mode */
1547   tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1548   if (!tmp || tmp_len != 4)
1549     goto out;
1550   SILC_GET32_MSB(mode, tmp);
1551
1552   /* Get notify type */
1553   tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1554   if (tmp && tmp_len != 2)
1555     goto out;
1556   if (tmp)
1557     SILC_GET16_MSB(ntype, tmp);
1558
1559   /* Get nickname */
1560   tmp = silc_argument_get_arg_type(args, 2, NULL);
1561   if (tmp) {
1562     char *tmp_nick = NULL;
1563
1564     silc_client_nickname_parse(client, conn, client_entry->nickname,
1565                                &tmp_nick);
1566
1567     /* If same nick, the client was new to us and has become "present"
1568        to network.  Send NULL as nick to application. */
1569     if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1570       tmp = NULL;
1571
1572     silc_free(tmp_nick);
1573   }
1574
1575   /* Get public key, if present */
1576   pk = silc_argument_get_arg_type(args, 5, &pk_len);
1577   if (pk && !client_entry->public_key) {
1578     if (silc_public_key_payload_decode(pk, pk_len, &public_key)) {
1579       client_entry->public_key = public_key;
1580       public_key = NULL;
1581     }
1582   }
1583
1584   /* Notify application. */
1585   NOTIFY(client, conn, type, client_entry, tmp, mode, ntype,
1586          client_entry->public_key);
1587
1588   client_entry->mode = mode;
1589
1590   /* If nickname was changed, remove the client entry unless the
1591      client is on some channel */
1592   /* XXX, why do we need to remove the client entry?? */
1593   if (tmp && ntype == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1594       !silc_hash_table_count(client_entry->channels))
1595     del_client = TRUE;
1596   else if (ntype == SILC_NOTIFY_TYPE_SIGNOFF ||
1597            ntype == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1598            ntype == SILC_NOTIFY_TYPE_KILLED)
1599     del_client = TRUE;
1600
1601   if (del_client) {
1602     silc_client_remove_from_channels(client, conn, client_entry);
1603     silc_client_del_client(client, conn, client_entry);
1604   }
1605
1606   if (public_key)
1607     silc_pkcs_public_key_free(public_key);
1608
1609  out:
1610   /** Notify processed */
1611   silc_client_unref_client(client, conn, client_entry);
1612   silc_fsm_next(fsm, silc_client_notify_processed);
1613   return SILC_FSM_CONTINUE;
1614 }