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