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