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