5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 Pekka Riikonen
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.
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.
22 #include "silcclient.h"
23 #include "client_internal.h"
25 /* Context used for resolving client, channel and server info. */
29 SilcSocketConnection sock;
30 } *SilcClientNotifyResolve;
32 SILC_TASK_CALLBACK(silc_client_notify_check_client)
34 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
35 SilcClient client = res->context;
36 SilcClientConnection conn = res->sock->user_data;
37 SilcClientID *client_id = res->packet;
38 silc_client_get_client_by_id_resolve(client, conn, client_id,
41 silc_socket_free(res->sock);
45 SILC_TASK_CALLBACK(silc_client_notify_del_client_cb)
47 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
48 SilcClient client = res->context;
49 SilcClientConnection conn = res->sock->user_data;
50 SilcClientID *client_id = res->packet;
51 SilcClientEntry client_entry;
52 client_entry = silc_client_get_client_by_id(client, conn, client_id);
54 silc_client_del_client(client, conn, client_entry);
56 silc_socket_free(res->sock);
60 /* Called when notify is received and some async operation (such as command)
61 is required before processing the notify message. This calls again the
62 silc_client_notify_by_server and reprocesses the original notify packet. */
64 static void silc_client_notify_by_server_pending(void *context, void *context2)
66 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
67 SilcClientCommandReplyContext reply =
68 (SilcClientCommandReplyContext)context2;
70 SILC_LOG_DEBUG(("Start"));
72 if (reply && !silc_command_get_status(reply->payload, NULL, NULL))
75 silc_client_notify_by_server(res->context, res->sock, res->packet);
78 silc_socket_free(res->sock);
79 silc_packet_context_free(res->packet);
83 /* Resets the channel entry's resolve_cmd_ident after whatever-thing
84 was resolved is completed. */
86 static void silc_client_channel_cond(void *context, void *context2)
88 SilcClientNotifyResolve res = (SilcClientNotifyResolve)context;
89 SilcClient client = res->context;
90 SilcClientConnection conn = res->sock->user_data;
91 SilcChannelID *channel_id = res->packet;
92 SilcChannelEntry channel;
93 channel = silc_client_get_channel_by_id(client, conn, channel_id);
95 channel->resolve_cmd_ident = 0;
96 silc_free(channel_id);
97 silc_socket_free(res->sock);
101 /* Function that starts waiting for the `cmd_ident' to arrive and
102 marks the channel info being resolved. */
104 static void silc_client_channel_set_wait(SilcClient client,
105 SilcClientConnection conn,
106 SilcChannelEntry channel,
107 SilcUInt16 cmd_ident)
109 SilcClientNotifyResolve res;
111 if (!channel->resolve_cmd_ident) {
112 res = silc_calloc(1, sizeof(*res));
113 res->context = client;
114 res->sock = silc_socket_dup(conn->sock);
115 res->packet = silc_id_dup(channel->id, SILC_ID_CHANNEL);
116 silc_client_command_pending(conn, SILC_COMMAND_NONE, cmd_ident,
117 silc_client_channel_cond, res);
118 channel->resolve_cmd_ident = cmd_ident;
122 /* Attaches to the channel's resolving cmd ident and calls the
123 notify handling with `packet' after it's received. */
125 static void silc_client_channel_wait(SilcClient client,
126 SilcClientConnection conn,
127 SilcChannelEntry channel,
128 SilcPacketContext *packet)
130 SilcClientNotifyResolve res;
132 if (!channel->resolve_cmd_ident)
135 res = silc_calloc(1, sizeof(*res));
136 res->packet = silc_packet_context_dup(packet);
137 res->context = client;
138 res->sock = silc_socket_dup(conn->sock);
140 silc_client_command_pending(conn, SILC_COMMAND_NONE,
141 channel->resolve_cmd_ident,
142 silc_client_notify_by_server_pending, res);
145 /* Resolve client, channel or server information. */
147 static void silc_client_notify_by_server_resolve(SilcClient client,
148 SilcClientConnection conn,
149 SilcPacketContext *packet,
153 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
154 SilcBuffer idp = silc_id_payload_encode(id, id_type);
156 res->packet = silc_packet_context_dup(packet);
157 res->context = client;
158 res->sock = silc_socket_dup(conn->sock);
160 /* For client resolving use WHOIS, and otherwise use IDENTIFY */
161 if (id_type == SILC_ID_CLIENT) {
162 silc_client_command_register(client, SILC_COMMAND_WHOIS, NULL, NULL,
163 silc_client_command_reply_whois_i, 0,
165 silc_client_command_send(client, conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
166 1, 4, idp->data, idp->len);
167 silc_client_command_pending(conn, SILC_COMMAND_WHOIS, conn->cmd_ident,
168 silc_client_notify_by_server_pending, res);
170 silc_client_command_register(client, SILC_COMMAND_IDENTIFY, NULL, NULL,
171 silc_client_command_reply_identify_i, 0,
173 silc_client_command_send(client, conn, SILC_COMMAND_IDENTIFY,
174 conn->cmd_ident, 1, 5, idp->data, idp->len);
175 silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
176 silc_client_notify_by_server_pending, res);
178 silc_buffer_free(idp);
181 /* Received notify message from server */
183 void silc_client_notify_by_server(SilcClient client,
184 SilcSocketConnection sock,
185 SilcPacketContext *packet)
187 SilcBuffer buffer = packet->buffer;
188 SilcClientConnection conn = (SilcClientConnection)sock->user_data;
189 SilcNotifyPayload payload;
191 SilcArgumentPayload args;
195 SilcClientID *client_id = NULL;
196 SilcChannelID *channel_id = NULL;
197 SilcServerID *server_id = NULL;
198 SilcClientEntry client_entry = NULL;
199 SilcClientEntry client_entry2 = NULL;
200 SilcChannelEntry channel;
202 SilcServerEntry server;
204 SilcUInt32 tmp_len, mode;
206 SILC_LOG_DEBUG(("Start"));
208 payload = silc_notify_payload_parse(buffer->data, buffer->len);
212 type = silc_notify_get_type(payload);
213 args = silc_notify_get_args(payload);
218 case SILC_NOTIFY_TYPE_NONE:
219 /* Notify application */
220 client->internal->ops->notify(client, conn, type,
221 silc_argument_get_arg_type(args, 1, NULL));
224 case SILC_NOTIFY_TYPE_INVITE:
226 * Someone invited me to a channel. Find Client and Channel entries
227 * for the application.
230 SILC_LOG_DEBUG(("Notify: INVITE"));
233 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
237 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
241 /* Get the channel entry */
242 channel = silc_client_get_channel_by_id(client, conn, channel_id);
244 /* Get sender Client ID */
245 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
249 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
253 /* Find Client entry and if not found query it */
254 client_entry = silc_client_get_client_by_id(client, conn, client_id);
256 silc_client_notify_by_server_resolve(client, conn, packet,
257 SILC_ID_CLIENT, client_id);
261 /* Get the channel name */
262 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
266 /* Notify application */
267 client->internal->ops->notify(client, conn, type, channel, tmp,
271 case SILC_NOTIFY_TYPE_JOIN:
273 * Someone has joined to a channel. Get their ID and nickname and
274 * cache them for later use.
277 SILC_LOG_DEBUG(("Notify: JOIN"));
280 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
284 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
288 /* Get channel entry */
289 channel = silc_client_get_channel_by_id(client, conn, channel_id);
294 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
298 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
302 /* Find Client entry and if not found query it */
303 client_entry = silc_client_get_client_by_id(client, conn, client_id);
305 silc_client_channel_set_wait(client, conn, channel,
306 conn->cmd_ident + 1);
307 silc_client_notify_by_server_resolve(client, conn, packet,
308 SILC_ID_CLIENT, client_id);
312 /* If nickname or username hasn't been resolved, do so */
313 if (!client_entry->nickname || !client_entry->username) {
314 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
315 /* Attach to existing resolving */
316 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
317 res->packet = silc_packet_context_dup(packet);
318 res->context = client;
319 res->sock = silc_socket_dup(conn->sock);
320 silc_client_command_pending(conn, SILC_COMMAND_NONE,
321 client_entry->resolve_cmd_ident,
322 silc_client_notify_by_server_pending,
327 /* Do new resolving */
328 silc_client_channel_set_wait(client, conn, channel,
329 conn->cmd_ident + 1);
330 silc_client_notify_by_server_resolve(client, conn, packet,
331 SILC_ID_CLIENT, client_id);
332 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
333 client_entry->resolve_cmd_ident = conn->cmd_ident;
336 if (client_entry != conn->local_entry)
337 silc_client_nickname_format(client, conn, client_entry);
340 /* If information is being resolved for this channel, wait for it */
341 if (channel->resolve_cmd_ident) {
342 silc_client_channel_wait(client, conn, channel, packet);
346 /* Join the client to channel */
347 if (!silc_client_on_channel(channel, client_entry)) {
348 chu = silc_calloc(1, sizeof(*chu));
349 chu->client = client_entry;
350 chu->channel = channel;
351 silc_hash_table_add(channel->user_list, client_entry, chu);
352 silc_hash_table_add(client_entry->channels, channel, chu);
355 /* Notify application. The channel entry is sent last as this notify
356 is for channel but application don't know it from the arguments
358 client->internal->ops->notify(client, conn, type, client_entry, channel);
361 case SILC_NOTIFY_TYPE_LEAVE:
363 * Someone has left a channel. We will remove it from the channel but
364 * we'll keep it in the cache in case we'll need it later.
367 SILC_LOG_DEBUG(("Notify: LEAVE"));
370 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
374 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
378 /* Find Client entry */
380 silc_client_get_client_by_id(client, conn, client_id);
384 /* Get channel entry */
385 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
389 channel = silc_client_get_channel_by_id(client, conn, channel_id);
393 /* Remove client from channel */
394 chu = silc_client_on_channel(channel, client_entry);
396 silc_hash_table_del(client_entry->channels, channel);
397 silc_hash_table_del(channel->user_list, client_entry);
401 /* Some client implementations actually quit network by first doing
402 LEAVE and then immediately SIGNOFF. We'll check for this by doing
403 check for the client after 5 - 34 seconds. If it is not valid after
404 that we'll remove the client from cache. */
405 if (!silc_hash_table_count(client_entry->channels)) {
406 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
407 res->context = client;
408 res->sock = silc_socket_dup(conn->sock);
409 res->packet = silc_id_dup(client_id, SILC_ID_CLIENT);
410 silc_schedule_task_add(client->schedule, conn->sock->sock,
411 silc_client_notify_check_client, res,
412 (5 + (silc_rng_get_rn16(client->rng) % 29)),
413 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
416 /* Notify application. The channel entry is sent last as this notify
417 is for channel but application don't know it from the arguments
419 client->internal->ops->notify(client, conn, type, client_entry, channel);
422 case SILC_NOTIFY_TYPE_SIGNOFF:
424 * Someone left SILC. We'll remove it from all channels and from cache.
427 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
430 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
434 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
438 /* Find Client entry */
440 silc_client_get_client_by_id(client, conn, client_id);
444 /* Get signoff message */
445 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
449 /* Notify application */
450 client->internal->ops->notify(client, conn, type, client_entry, tmp);
452 /* Remove from all channels */
453 silc_client_remove_from_channels(client, conn, client_entry);
455 /* Remove from cache */
456 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
459 silc_client_del_client_entry(client, conn, client_entry);
462 case SILC_NOTIFY_TYPE_TOPIC_SET:
464 * Someone set the topic on a channel.
467 SILC_LOG_DEBUG(("Notify: TOPIC_SET"));
469 /* Get channel entry */
470 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
474 channel = silc_client_get_channel_by_id(client, conn, channel_id);
479 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
482 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
486 /* Find Client entry */
487 if (id_type == SILC_ID_CLIENT) {
488 /* Find Client entry */
490 client_entry = silc_client_get_client_by_id(client, conn, client_id);
492 silc_client_channel_set_wait(client, conn, channel,
493 conn->cmd_ident + 1);
494 silc_client_notify_by_server_resolve(client, conn, packet,
495 SILC_ID_CLIENT, client_id);
498 } else if (id_type == SILC_ID_SERVER) {
499 /* Find Server entry */
501 server = silc_client_get_server_by_id(client, conn, server_id);
503 silc_client_channel_set_wait(client, conn, channel,
504 conn->cmd_ident + 1);
505 silc_client_notify_by_server_resolve(client, conn, packet,
506 SILC_ID_SERVER, server_id);
507 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
511 server->resolve_cmd_ident = conn->cmd_ident;
516 /* If entry being resoled, wait for it before processing this notify */
517 if (server->resolve_cmd_ident) {
518 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
519 res->packet = silc_packet_context_dup(packet);
520 res->context = client;
521 res->sock = silc_socket_dup(conn->sock);
522 silc_client_command_pending(conn, SILC_COMMAND_NONE,
523 server->resolve_cmd_ident,
524 silc_client_notify_by_server_pending, res);
528 /* Save the pointer to the client_entry pointer */
529 client_entry = (SilcClientEntry)server;
531 /* Find Channel entry */
532 silc_free(channel_id);
534 client_entry = (SilcClientEntry)
535 silc_client_get_channel_by_id(client, conn, channel_id);
537 silc_client_channel_set_wait(client, conn, channel,
538 conn->cmd_ident + 1);
539 silc_client_notify_by_server_resolve(client, conn, packet,
540 SILC_ID_CHANNEL, channel_id);
546 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
550 /* If information is being resolved for this channel, wait for it */
551 if (channel->resolve_cmd_ident) {
552 silc_client_channel_wait(client, conn, channel, packet);
557 silc_free(channel->topic);
558 channel->topic = silc_memdup(tmp, strlen(tmp));
561 /* Notify application. The channel entry is sent last as this notify
562 is for channel but application don't know it from the arguments
564 client->internal->ops->notify(client, conn, type, id_type,
565 client_entry, tmp, channel);
569 case SILC_NOTIFY_TYPE_NICK_CHANGE:
571 * Someone changed their nickname. If we don't have entry for the new
572 * ID we will query it and return here after it's done. After we've
573 * returned we fetch the old entry and free it and notify the
577 SILC_LOG_DEBUG(("Notify: NICK_CHANGE"));
579 /* Get old Client ID */
580 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
584 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
589 if (conn->local_id && SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
592 /* Find old Client entry */
593 client_entry = silc_client_get_client_by_id(client, conn, client_id);
596 silc_free(client_id);
599 /* Wait for resolving if necessary */
600 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
601 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
602 res->packet = silc_packet_context_dup(packet);
603 res->context = client;
604 res->sock = silc_socket_dup(conn->sock);
605 silc_client_command_pending(conn, SILC_COMMAND_NONE,
606 client_entry->resolve_cmd_ident,
607 silc_client_notify_by_server_pending, res);
611 client_entry->valid = FALSE;
613 /* Get new Client ID */
614 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
618 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
622 /* Take the nickname */
623 tmp = silc_argument_get_arg_type(args, 3, NULL);
627 /* Check whether nickname changed at all. It is possible that nick
628 change notify is received but nickname didn't change, only the
629 ID changes. Check whether the hashes in the Client ID match, if
630 they do nickname didn't change. */
631 if (SILC_ID_COMPARE_HASH(client_entry->id, client_id) &&
632 silc_utf8_strcasecmp(tmp, client_entry->nickname)) {
633 /* Nickname didn't change. Update only Client ID. */
635 /* Normalize nickname */
636 tmp = silc_identifier_check(tmp, strlen(tmp),
637 SILC_STRING_UTF8, 128, NULL);
641 silc_idcache_del_by_context(conn->internal->client_cache,
643 silc_free(client_entry->id);
644 client_entry->id = silc_id_dup(client_id, SILC_ID_CLIENT);
645 silc_idcache_add(conn->internal->client_cache, tmp,
646 client_entry->id, client_entry, 0, NULL);
648 /* Notify application */
649 client->internal->ops->notify(client, conn, type,
650 client_entry, client_entry);
654 /* Create new client entry, and save all old information with the
655 new nickname and client ID */
656 client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
657 client_entry->realname,
658 silc_id_dup(client_id,
663 if (client_entry->server)
664 client_entry2->server = strdup(client_entry->server);
665 if (client_entry->username)
666 client_entry2->username = strdup(client_entry->username);
667 if (client_entry->hostname)
668 client_entry2->hostname = strdup(client_entry->hostname);
669 client_entry2->fingerprint = client_entry->fingerprint;
670 client_entry2->fingerprint_len = client_entry->fingerprint_len;
671 client_entry->fingerprint = NULL;
672 client_entry->fingerprint_len = 0;
673 silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
676 /* Remove the old from cache */
677 silc_idcache_del_by_context(conn->internal->client_cache, client_entry);
679 /* Replace old ID entry with new one on all channels. */
680 silc_client_replace_from_channels(client, conn, client_entry,
683 /* Notify application */
684 client->internal->ops->notify(client, conn, type,
685 client_entry, client_entry2);
687 /* Free old client entry */
688 silc_client_del_client_entry(client, conn, client_entry);
692 case SILC_NOTIFY_TYPE_CMODE_CHANGE:
695 * Someone changed a channel mode
697 char *passphrase, *cipher, *hmac;
698 SilcPublicKey founder_key = NULL;
699 SilcBufferStruct chpks;
701 SILC_LOG_DEBUG(("Notify: CMODE_CHANGE"));
703 /* Get channel entry */
704 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
708 channel = silc_client_get_channel_by_id(client, conn, channel_id);
713 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
716 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
720 /* Find Client entry */
721 if (id_type == SILC_ID_CLIENT) {
722 /* Find Client entry */
724 client_entry = silc_client_get_client_by_id(client, conn, client_id);
726 silc_client_channel_set_wait(client, conn, channel,
727 conn->cmd_ident + 1);
728 silc_client_notify_by_server_resolve(client, conn, packet,
729 SILC_ID_CLIENT, client_id);
733 if (!client_entry->nickname) {
734 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
735 /* Attach to existing resolving */
736 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
737 res->packet = silc_packet_context_dup(packet);
738 res->context = client;
739 res->sock = silc_socket_dup(conn->sock);
740 silc_client_command_pending(conn, SILC_COMMAND_NONE,
741 client_entry->resolve_cmd_ident,
742 silc_client_notify_by_server_pending,
747 /* Do new resolving */
748 silc_client_channel_set_wait(client, conn, channel,
749 conn->cmd_ident + 1);
750 silc_client_notify_by_server_resolve(client, conn, packet,
751 SILC_ID_CLIENT, client_id);
752 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
753 client_entry->resolve_cmd_ident = conn->cmd_ident;
756 } else if (id_type == SILC_ID_SERVER) {
757 /* Find Server entry */
759 server = silc_client_get_server_by_id(client, conn, server_id);
761 silc_client_channel_set_wait(client, conn, channel,
762 conn->cmd_ident + 1);
763 silc_client_notify_by_server_resolve(client, conn, packet,
764 SILC_ID_SERVER, server_id);
765 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
769 server->resolve_cmd_ident = conn->cmd_ident;
774 /* If entry being resoled, wait for it before processing this notify */
775 if (server->resolve_cmd_ident) {
776 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
777 res->packet = silc_packet_context_dup(packet);
778 res->context = client;
779 res->sock = silc_socket_dup(conn->sock);
780 silc_client_command_pending(conn, SILC_COMMAND_NONE,
781 server->resolve_cmd_ident,
782 silc_client_notify_by_server_pending,
787 /* Save the pointer to the client_entry pointer */
788 client_entry = (SilcClientEntry)server;
790 /* Find Channel entry */
791 silc_free(channel_id);
793 client_entry = (SilcClientEntry)
794 silc_client_get_channel_by_id(client, conn, channel_id);
796 silc_client_channel_set_wait(client, conn, channel,
797 conn->cmd_ident + 1);
798 silc_client_notify_by_server_resolve(client, conn, packet,
799 SILC_ID_CHANNEL, channel_id);
805 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
809 SILC_GET32_MSB(mode, tmp);
811 /* If information is being resolved for this channel, wait for it */
812 if (channel->resolve_cmd_ident) {
813 silc_client_channel_wait(client, conn, channel, packet);
817 /* Save the new mode */
818 channel->mode = mode;
821 cipher = silc_argument_get_arg_type(args, 3, &tmp_len);
824 hmac = silc_argument_get_arg_type(args, 4, &tmp_len);
826 unsigned char hash[SILC_HASH_MAXLEN];
829 silc_hmac_free(channel->hmac);
830 if (!silc_hmac_alloc(hmac, NULL, &channel->hmac))
833 silc_hash_make(silc_hmac_get_hash(channel->hmac),
834 channel->key, channel->key_len / 8,
836 silc_hmac_set_key(channel->hmac, hash,
837 silc_hash_len(silc_hmac_get_hash(channel->hmac)));
838 memset(hash, 0, sizeof(hash));
841 /* Get the passphrase if it was set */
842 passphrase = silc_argument_get_arg_type(args, 5, &tmp_len);
844 /* Get the channel founder key if it was set */
845 tmp = silc_argument_get_arg_type(args, 6, &tmp_len);
847 if (!silc_pkcs_public_key_payload_decode(tmp, tmp_len, &founder_key))
852 tmp = silc_argument_get_arg_type(args, 8, &tmp_len);
853 if (tmp && tmp_len == 4)
854 SILC_GET32_MSB(channel->user_limit, tmp);
855 if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT))
856 channel->user_limit = 0;
858 /* Get the channel public key that was added or removed */
859 tmp = silc_argument_get_arg_type(args, 7, &tmp_len);
861 silc_buffer_set(&chpks, tmp, tmp_len);
863 /* Notify application. The channel entry is sent last as this notify
864 is for channel but application don't know it from the arguments
866 client->internal->ops->notify(client, conn, type, id_type,
867 client_entry, mode, cipher, hmac,
868 passphrase, founder_key,
869 tmp ? &chpks : NULL, channel);
872 silc_pkcs_public_key_free(founder_key);
876 case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
878 * Someone changed user's mode on a channel
881 SILC_LOG_DEBUG(("Notify: CUMODE_CHANGE"));
883 /* Get channel entry */
884 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
888 channel = silc_client_get_channel_by_id(client, conn, channel_id);
893 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
896 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
900 /* Find Client entry */
901 if (id_type == SILC_ID_CLIENT) {
902 /* Find Client entry */
904 client_entry = silc_client_get_client_by_id(client, conn, client_id);
906 silc_client_channel_set_wait(client, conn, channel,
907 conn->cmd_ident + 1);
908 silc_client_notify_by_server_resolve(client, conn, packet,
909 SILC_ID_CLIENT, client_id);
913 if (!client_entry->nickname) {
914 if (client_entry->status & SILC_CLIENT_STATUS_RESOLVING) {
915 /* Attach to existing resolving */
916 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
917 res->packet = silc_packet_context_dup(packet);
918 res->context = client;
919 res->sock = silc_socket_dup(conn->sock);
920 silc_client_command_pending(conn, SILC_COMMAND_NONE,
921 client_entry->resolve_cmd_ident,
922 silc_client_notify_by_server_pending,
927 /* Do new resolving */
928 silc_client_channel_set_wait(client, conn, channel,
929 conn->cmd_ident + 1);
930 silc_client_notify_by_server_resolve(client, conn, packet,
931 SILC_ID_CLIENT, client_id);
932 client_entry->status |= SILC_CLIENT_STATUS_RESOLVING;
933 client_entry->resolve_cmd_ident = conn->cmd_ident;
936 } else if (id_type == SILC_ID_SERVER) {
937 /* Find Server entry */
939 server = silc_client_get_server_by_id(client, conn, server_id);
941 silc_client_channel_set_wait(client, conn, channel,
942 conn->cmd_ident + 1);
943 silc_client_notify_by_server_resolve(client, conn, packet,
944 SILC_ID_SERVER, server_id);
945 server = silc_client_add_server(client, conn, NULL, NULL, server_id);
949 server->resolve_cmd_ident = conn->cmd_ident;
954 /* If entry being resoled, wait for it before processing this notify */
955 if (server->resolve_cmd_ident) {
956 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
957 res->packet = silc_packet_context_dup(packet);
958 res->context = client;
959 res->sock = silc_socket_dup(conn->sock);
960 silc_client_command_pending(conn, SILC_COMMAND_NONE,
961 server->resolve_cmd_ident,
962 silc_client_notify_by_server_pending, res);
966 /* Save the pointer to the client_entry pointer */
967 client_entry = (SilcClientEntry)server;
969 /* Find Channel entry */
970 silc_free(channel_id);
972 client_entry = (SilcClientEntry)
973 silc_client_get_channel_by_id(client, conn, channel_id);
975 silc_client_channel_set_wait(client, conn, channel,
976 conn->cmd_ident + 1);
977 silc_client_notify_by_server_resolve(client, conn, packet,
978 SILC_ID_CHANNEL, channel_id);
984 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
988 SILC_GET32_MSB(mode, tmp);
990 /* If information is being resolved for this channel, wait for it */
991 if (channel->resolve_cmd_ident) {
992 silc_client_channel_wait(client, conn, channel, packet);
996 /* Get target Client ID */
997 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1001 silc_free(client_id);
1002 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1006 /* Find target Client entry */
1008 silc_client_get_client_by_id(client, conn, client_id);
1009 if (!client_entry2) {
1010 silc_client_notify_by_server_resolve(client, conn, packet,
1011 SILC_ID_CLIENT, client_id);
1016 chu = silc_client_on_channel(channel, client_entry2);
1020 /* Notify application. The channel entry is sent last as this notify
1021 is for channel but application don't know it from the arguments
1023 client->internal->ops->notify(client, conn, type,
1024 id_type, client_entry, mode,
1025 client_entry2, channel);
1028 case SILC_NOTIFY_TYPE_MOTD:
1030 * Received Message of the day
1033 SILC_LOG_DEBUG(("Notify: MOTD"));
1036 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1040 /* Notify application */
1041 client->internal->ops->notify(client, conn, type, tmp);
1044 case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
1046 * Router has enforced a new ID to a channel. Let's change the old
1047 * ID to the one provided here.
1050 SILC_LOG_DEBUG(("Notify: CHANNEL_CHANGE"));
1052 /* Get the old ID */
1053 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1056 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1060 /* Get the channel entry */
1061 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1065 silc_free(channel_id);
1068 /* Get the new ID */
1069 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1072 channel_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1076 /* Replace the Channel ID */
1077 if (silc_client_replace_channel_id(client, conn, channel, channel_id))
1080 /* Notify application */
1081 client->internal->ops->notify(client, conn, type, channel, channel);
1084 case SILC_NOTIFY_TYPE_KICKED:
1086 * A client (maybe me) was kicked from a channel
1089 SILC_LOG_DEBUG(("Notify: KICKED"));
1092 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1096 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1100 /* Find Client entry */
1101 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1105 /* Get channel entry */
1106 channel_id = silc_id_str2id(packet->dst_id, packet->dst_id_len,
1110 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1114 /* From protocol version 1.1 we get the kicker's client ID as well */
1115 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1117 silc_free(client_id);
1118 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1122 /* Find kicker's client entry and if not found resolve it */
1123 client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
1124 if (!client_entry2) {
1125 silc_client_notify_by_server_resolve(client, conn, packet,
1126 SILC_ID_CLIENT, client_id);
1129 if (client_entry2 != conn->local_entry)
1130 silc_client_nickname_format(client, conn, client_entry2);
1135 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1137 /* Remove kicked client from channel */
1138 if (client_entry != conn->local_entry) {
1139 chu = silc_client_on_channel(channel, client_entry);
1141 silc_hash_table_del(client_entry->channels, channel);
1142 silc_hash_table_del(channel->user_list, client_entry);
1147 /* Notify application. The channel entry is sent last as this notify
1148 is for channel but application don't know it from the arguments
1150 client->internal->ops->notify(client, conn, type, client_entry, tmp,
1151 client_entry2, channel);
1153 /* Remove kicked client (us) from channel */
1154 if (client_entry == conn->local_entry) {
1155 /* If I was kicked from channel, remove the channel */
1156 if (conn->current_channel == channel)
1157 conn->current_channel = NULL;
1158 silc_client_del_channel(client, conn, channel);
1160 if (!silc_hash_table_count(client_entry->channels)) {
1161 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1162 res->context = client;
1163 res->sock = silc_socket_dup(conn->sock);
1164 res->packet = silc_id_dup(client_entry->id, SILC_ID_CLIENT);
1165 silc_schedule_task_add(client->schedule, conn->sock->sock,
1166 silc_client_notify_check_client, res,
1167 (5 + (silc_rng_get_rn16(client->rng) % 529)),
1168 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1173 case SILC_NOTIFY_TYPE_KILLED:
1176 * A client (maybe me) was killed from the network.
1179 SilcUInt32 comment_len;
1181 SILC_LOG_DEBUG(("Notify: KILLED"));
1184 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1188 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1192 /* Find Client entry */
1193 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1198 comment = silc_argument_get_arg_type(args, 2, &comment_len);
1200 /* From protocol version 1.1 we get killer's client ID as well */
1201 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1203 silc_free(client_id);
1205 id = silc_id_payload_parse_id(tmp, tmp_len, &id_type);
1209 /* Find Client entry */
1210 if (id_type == SILC_ID_CLIENT) {
1211 /* Find Client entry */
1213 client_entry2 = silc_client_get_client_by_id(client, conn,
1215 if (!client_entry) {
1216 silc_client_notify_by_server_resolve(client, conn, packet,
1217 SILC_ID_CLIENT, client_id);
1220 } else if (id_type == SILC_ID_SERVER) {
1221 /* Find Server entry */
1223 server = silc_client_get_server_by_id(client, conn, server_id);
1225 silc_client_notify_by_server_resolve(client, conn, packet,
1226 SILC_ID_SERVER, server_id);
1227 server = silc_client_add_server(client, conn, NULL, NULL,
1232 server->resolve_cmd_ident = conn->cmd_ident;
1237 if (server->resolve_cmd_ident) {
1238 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1239 res->packet = silc_packet_context_dup(packet);
1240 res->context = client;
1241 res->sock = silc_socket_dup(conn->sock);
1242 silc_client_command_pending(conn, SILC_COMMAND_NONE,
1243 server->resolve_cmd_ident,
1244 silc_client_notify_by_server_pending,
1249 /* Save the pointer to the client_entry pointer */
1250 client_entry2 = (SilcClientEntry)server;
1252 /* Find Channel entry */
1254 channel = silc_client_get_channel_by_id(client, conn, channel_id);
1256 silc_client_notify_by_server_resolve(client, conn, packet,
1257 SILC_ID_CHANNEL, channel_id);
1261 /* Save the pointer to the client_entry pointer */
1262 client_entry2 = (SilcClientEntry)channel;
1263 silc_free(channel_id);
1268 /* Notify application. */
1269 client->internal->ops->notify(client, conn, type, client_entry,
1270 comment, id_type, client_entry2);
1272 if (client_entry != conn->local_entry)
1273 /* Remove the client from all channels and free it */
1274 silc_client_del_client(client, conn, client_entry);
1278 case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
1281 * A server quit the SILC network and some clients must be removed
1282 * from channels as they quit as well.
1284 SilcClientEntry *clients = NULL;
1285 SilcUInt32 clients_count = 0;
1288 SILC_LOG_DEBUG(("Notify: SIGNOFF"));
1290 for (i = 1; i < silc_argument_get_arg_num(args); i++) {
1292 tmp = silc_argument_get_arg_type(args, i + 1, &tmp_len);
1294 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1298 /* Get the client entry */
1299 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1301 clients = silc_realloc(clients, sizeof(*clients) *
1302 (clients_count + 1));
1303 clients[clients_count] = client_entry;
1306 silc_free(client_id);
1311 /* Notify application. We don't keep server entries so the server
1312 entry is returned as NULL. The client's are returned as array
1313 of SilcClientEntry pointers. */
1314 client->internal->ops->notify(client, conn, type, NULL,
1315 clients, clients_count);
1317 for (i = 0; i < clients_count; i++) {
1318 /* Remove client from all channels */
1319 client_entry = clients[i];
1320 if (client_entry == conn->local_entry)
1323 /* Remove the client from all channels and free it */
1324 silc_client_del_client(client, conn, client_entry);
1331 case SILC_NOTIFY_TYPE_ERROR:
1334 * Some has occurred and server is notifying us about it.
1338 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1339 if (!tmp && tmp_len != 1)
1341 error = (SilcStatus)tmp[0];
1343 SILC_LOG_DEBUG(("Notify: ERROR (%d)", error));
1345 if (error == SILC_STATUS_ERR_NO_SUCH_CLIENT_ID) {
1346 tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
1348 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1351 client_entry = silc_client_get_client_by_id(client, conn,
1354 silc_client_del_client(client, conn, client_entry);
1358 /* Notify application. */
1359 client->internal->ops->notify(client, conn, type, error);
1363 case SILC_NOTIFY_TYPE_WATCH:
1366 * Received notify about some client we are watching
1368 SilcNotifyType notify = 0;
1369 SilcBool del_client = FALSE;
1372 SilcPublicKey public_key = NULL;
1374 SILC_LOG_DEBUG(("Notify: WATCH"));
1376 /* Get sender Client ID */
1377 tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
1380 client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
1384 /* Find Client entry and if not found query it */
1385 client_entry = silc_client_get_client_by_id(client, conn, client_id);
1386 if (!client_entry) {
1387 silc_client_notify_by_server_resolve(client, conn, packet,
1388 SILC_ID_CLIENT, client_id);
1393 tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
1394 if (!tmp || tmp_len != 4)
1396 SILC_GET32_MSB(mode, tmp);
1398 /* Get notify type */
1399 tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
1400 if (tmp && tmp_len != 2)
1403 SILC_GET16_MSB(notify, tmp);
1406 tmp = silc_argument_get_arg_type(args, 2, NULL);
1408 char *tmp_nick = NULL;
1410 if (client->internal->params->nickname_parse)
1411 client->internal->params->nickname_parse(client_entry->nickname,
1414 tmp_nick = strdup(tmp);
1416 /* If same nick, the client was new to us and has become "present"
1417 to network. Send NULL as nick to application. */
1418 if (tmp_nick && silc_utf8_strcasecmp(tmp, tmp_nick))
1421 silc_free(tmp_nick);
1424 /* Get public key, if present */
1425 pk = silc_argument_get_arg_type(args, 5, &pk_len);
1426 if (pk && !client_entry->public_key) {
1427 if (silc_pkcs_public_key_payload_decode(pk, pk_len, &public_key)) {
1428 client_entry->public_key = public_key;
1433 /* Notify application. */
1434 client->internal->ops->notify(client, conn, type, client_entry,
1436 client_entry->public_key);
1438 client_entry->mode = mode;
1440 /* If nickname was changed, remove the client entry unless the
1441 client is on some channel */
1442 if (tmp && notify == SILC_NOTIFY_TYPE_NICK_CHANGE &&
1443 !silc_hash_table_count(client_entry->channels))
1445 else if (notify == SILC_NOTIFY_TYPE_SIGNOFF ||
1446 notify == SILC_NOTIFY_TYPE_SERVER_SIGNOFF ||
1447 notify == SILC_NOTIFY_TYPE_KILLED)
1451 SilcClientNotifyResolve res = silc_calloc(1, sizeof(*res));
1452 res->context = client;
1453 res->sock = silc_socket_dup(conn->sock);
1454 res->packet = client_id;
1456 silc_schedule_task_add(client->schedule, conn->sock->sock,
1457 silc_client_notify_del_client_cb, res,
1458 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
1461 silc_pkcs_public_key_free(public_key);
1470 silc_notify_payload_free(payload);
1471 silc_free(client_id);
1472 silc_free(channel_id);
1473 silc_free(server_id);