+/* Send notify message to all clients the client has joined. It is quaranteed
+ that the message is sent only once to a client (ie. if a client is joined
+ on two same channel it will receive only one notify message). Also, this
+ sends only to local clients (locally connected if we are server, and to
+ local servers if we are router). */
+
+void silc_server_send_notify_on_channels(SilcServer server,
+ SilcClientEntry client,
+ SilcNotifyType type,
+ unsigned int argc, ...)
+{
+ int i, j, k;
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientEntry c;
+ SilcClientEntry *sent_clients = NULL;
+ unsigned int sent_clients_count = 0;
+ SilcServerEntry *routed = NULL;
+ unsigned int routed_count = 0;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcCipher cipher;
+ SilcHmac hmac;
+ SilcBuffer packet;
+ unsigned char *data;
+ unsigned int data_len;
+ int force_send = FALSE;
+ va_list ap;
+
+ if (!client->channel_count)
+ return;
+
+ va_start(ap, argc);
+ packet = silc_notify_payload_encode(type, argc, ap);
+ data = packet->data;
+ data_len = packet->len;
+
+ /* Set the packet context pointers. */
+ packetdata.flags = 0;
+ packetdata.type = SILC_PACKET_NOTIFY;
+ packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+ packetdata.src_id_len = SILC_ID_SERVER_LEN;
+ packetdata.src_id_type = SILC_ID_SERVER;
+ packetdata.rng = server->rng;
+
+ for (i = 0; i < client->channel_count; i++) {
+ channel = client->channel[i];
+
+ /* Send the message to clients on the channel's client list. */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ c = chl->client;
+
+ /* Check if we have sent the packet to this client already */
+ for (k = 0; k < sent_clients_count; k++)
+ if (sent_clients[k] == c)
+ break;
+ if (k < sent_clients_count)
+ continue;
+
+ /* If we are router and if this client has router set it is not
+ locally connected client and we will route the message to the
+ router set in the client. */
+ if (c && c->router && server->server_type == SILC_ROUTER) {
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == c->router)
+ break;
+ if (k < routed_count)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)c->router->connection;
+ cipher = c->router->send_key;
+ hmac = c->router->hmac;
+
+ packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
+ packetdata.dst_id_len = SILC_ID_SERVER_LEN;
+ packetdata.dst_id_type = SILC_ID_SERVER;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ cipher, hmac, data,
+ data_len, FALSE, force_send);
+
+ silc_free(packetdata.dst_id);
+
+ /* We want to make sure that the packet is routed to same router
+ only once. Mark this route as sent route. */
+ k = routed_count;
+ routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+ routed[k] = c->router;
+ routed_count++;
+
+ continue;
+ }
+
+ /* Send to locally connected client */
+ if (c) {
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)c->connection;
+ cipher = c->send_key;
+ hmac = c->hmac;
+
+ packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
+ packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
+ packetdata.dst_id_type = SILC_ID_CLIENT;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ cipher, hmac, data,
+ data_len, FALSE, force_send);
+
+ silc_free(packetdata.dst_id);
+
+ /* Make sure that we send the notify only once per client. */
+ sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) *
+ (sent_clients_count + 1));
+ sent_clients[sent_clients_count] = c;
+ sent_clients_count++;
+ }
+ }
+ }
+
+ if (routed_count)
+ silc_free(routed);
+ if (sent_clients_count)
+ silc_free(sent_clients);
+ silc_free(packetdata.src_id);
+}
+