+Thu Feb 1 21:32:27 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed some minor bugs in client when sending WHOIS command. The
+ arguments was in wrong order.
+
+ * Removed statis function add_to_channel from server in
+ silcd/command.c that was previously used with the joining but
+ is obsolete now.
+
+ * Tested USERS command in router environment successfully with two
+ routers, two servers and two clients.
+
+Thu Feb 1 00:54:26 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Reorganized the USERS command and command reply in client library
+ in lib/silcclient/command.c and lib/silcclient/command_reply.c.
+ When the command is given by user we register a pending command
+ callback that will reprocess the command after the reply has been
+ received from the server. When reprocessing the packet we then
+ display the information. Thus, the USERS information is displayed
+ now in the command callback instead of in the command reply
+ callback. The processing of the command is same as previously
+ when server has sent the command reply in the JOINing process.
+
+ * Added to USERS command in silcd/command_reply.c to join the client,
+ we didn't use to know about, to the channel after we've created
+ a client entry for it. Also, for clienet we did know already still
+ check whether it is on the channel or not and add it if not.
+
+ * Removed silc_server_command_join_notify as the function and its
+ use was obsolete.
+
Tue Jan 30 22:39:15 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Changed the client's pending command handling to the same as the
static void silc_server_command_free(SilcServerCommandContext cmd);
void silc_server_command_send_users(SilcServer server,
SilcSocketConnection sock,
- SilcChannelEntry channel);
+ SilcChannelEntry channel,
+ int pending);
/* Server command list. */
SilcServerCommand silc_command_list[] =
int i, k;
/* If client ID is in the command it must be used instead of nickname */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
if (!tmp) {
/* No ID, get the nickname@server string and parse it. */
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count;
+ int count = 0, clients_count = 0;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
unsigned int client_id_count = 0;
{
SilcServer server = cmd->server;
char *nick = NULL, *server_name = NULL;
- int count = 0, clients_count;
+ int count = 0, clients_count = 0;
SilcClientEntry *clients = NULL, entry;
SilcClientID **client_id = NULL;
unsigned int client_id_count = 0;
if (!clients) {
/* Such a client really does not exist in the SILC network. */
- silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NO_SUCH_NICK,
- 3, nick, strlen(nick));
+ if (!client_id_count) {
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_NICK,
+ 3, nick, strlen(nick));
+ } else {
+ SilcBuffer idp = silc_id_payload_encode(client_id[0], SILC_ID_CLIENT);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID,
+ 2, idp->data, idp->len);
+ silc_buffer_free(idp);
+ }
goto out;
}
{
}
-typedef struct {
- char *channel_name;
- char *nickname;
- char *username;
- char *hostname;
- SilcChannelEntry channel;
- SilcServer server;
- SilcClientEntry client;
-} JoinInternalContext;
-
-SILC_TASK_CALLBACK(silc_server_command_join_notify)
-{
- JoinInternalContext *ctx = (JoinInternalContext *)context;
-
- if (ctx->channel->key && ctx->channel->key_len) {
- SilcBuffer clidp;
-
- clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
-
- silc_server_send_notify_to_channel(ctx->server, ctx->channel, FALSE,
- SILC_NOTIFY_TYPE_JOIN, 1,
- clidp->data, clidp->len);
-#if 0
- /* Send NEW_CHANNEL_USER packet to primary route */
- silc_server_send_new_channel_user(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE,
- channel->id, SILC_ID_CHANNEL_LEN,
- client->id, SILC_ID_CLIENT_LEN);
-#endif
-
- /* Send USERS command reply to the joined channel so the user sees who
- is currently on the channel. */
- silc_server_command_send_users(ctx->server, ctx->client->connection,
- ctx->channel);
-
- silc_buffer_free(clidp);
- silc_free(ctx);
- } else {
- silc_task_register(ctx->server->timeout_queue, fd,
- silc_server_command_join_notify, context,
- 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
- }
-}
-
/* Assembles USERS command and executes it. This is called when client
joins to a channel and we wan't to send USERS command reply to the
client. */
void silc_server_command_send_users(SilcServer server,
SilcSocketConnection sock,
- SilcChannelEntry channel)
+ SilcChannelEntry channel,
+ int pending)
{
SilcServerCommandContext cmd;
SilcBuffer buffer, idp;
SilcPacketContext *packet = silc_packet_context_alloc();
+ /* Create USERS command packet and process it. */
idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 0, 1,
1, idp->data, idp->len);
cmd->packet = silc_packet_context_dup(packet);
cmd->pending = FALSE;
- silc_server_command_users((void *)cmd);
+ if (pending) {
+ /* If this function was called from pending command then instead of
+ processing the command now, register a pending command callback which
+ will process it after we've received the automatic USERS command
+ reply. */
+ silc_server_command_pending(server, SILC_COMMAND_USERS, 0,
+ silc_server_command_users, (void *)cmd);
+ cmd->pending = TRUE;
+ silc_free(buffer);
+ silc_free(idp);
+ return;
+ }
+ /* Process USERS command. */
+ silc_server_command_users((void *)cmd);
+
silc_free(buffer);
silc_free(idp);
silc_packet_context_free(packet);
}
-/* Internal routine that is called after router has replied to server's
- JOIN command it forwarded to the router. The route has joined and possibly
- creaetd the channel. This function adds the client to the channel's user
- list. */
-
-SILC_SERVER_CMD_FUNC(add_to_channel)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcClientEntry client;
- SilcChannelEntry channel;
- SilcChannelClientEntry chl;
- char *channel_name;
-
- /* Get channel name */
- channel_name = silc_argument_get_arg_type(cmd->args, 1, NULL);
-
- /* Get client entry */
- client = (SilcClientEntry)cmd->sock->user_data;
-
- /* Get channel entry */
- channel = silc_idlist_find_channel_by_name(server->local_list,
- channel_name, NULL);
- if (channel) {
- /* Join the client to the channel by adding it to channel's user list.
- Add also the channel to client entry's channels list for fast cross-
- referencing. */
- chl = silc_calloc(1, sizeof(*chl));
- //chl->mode = SILC_CHANNEL_UMODE_CHANOP | SILC_CHANNEL_UMODE_CHANFO;
- chl->client = client;
- chl->channel = channel;
- silc_list_add(channel->user_list, chl);
- silc_list_add(client->channels, chl);
- }
-
- silc_server_command_free(cmd);
-}
-
/* Internal routine to join channel. The channel sent to this function
has been either created or resolved from ID lists. This joins the sent
client to the channel. */
silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
reply->data, reply->len, FALSE);
- if (!cmd->pending)
+ if (!cmd->pending) {
/* Send JOIN notify to locally connected clients on the channel */
silc_server_send_notify_to_channel(server, channel, FALSE,
SILC_NOTIFY_TYPE_JOIN, 1,
clidp->data, clidp->len);
- /* Send NEW_CHANNEL_USER packet to our primary router */
- if (!cmd->pending && !server->standalone)
- silc_server_send_new_channel_user(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE,
- channel->id, SILC_ID_CHANNEL_LEN,
- client->id, SILC_ID_CLIENT_LEN);
+ /* Send NEW_CHANNEL_USER packet to our primary router */
+ if (!server->standalone)
+ silc_server_send_new_channel_user(server, server->router->connection,
+ server->server_type == SILC_SERVER ?
+ FALSE : TRUE,
+ channel->id, SILC_ID_CHANNEL_LEN,
+ client->id, SILC_ID_CLIENT_LEN);
+ }
/* Send USERS command reply to the joined channel so the user sees who
is currently on the channel. */
- silc_server_command_send_users(server, sock, channel);
-
- /*
-
- FAQ:
-
- * Kuinka USERS komento händlätään serverissä kun router lähettää sen
- serverille joka on lähettäny sille clientin puolesta JOIN komennon?
-
- R: Serverin pitää ymmärtää USERS comman replyjä.
-
- */
+ silc_server_command_send_users(server, sock, channel, cmd->pending);
silc_buffer_free(reply);
silc_buffer_free(clidp);
SilcChannelClientEntry chl;
SilcChannelID *id;
SilcBuffer packet;
- unsigned char *tmp;
- unsigned int tmp_len;
+ unsigned char *channel_id;
+ unsigned int channel_id_len;
SilcBuffer client_id_list;
SilcBuffer client_mode_list;
SilcBuffer idp;
+ unsigned char lc[4];
+ unsigned int list_count = 0;
unsigned short ident = silc_command_get_ident(cmd->payload);
SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_USERS, cmd, 1, 2);
/* Get Channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!tmp) {
+ channel_id = silc_argument_get_arg_type(cmd->args, 1, &channel_id_len);
+ if (!channel_id) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_USERS,
SILC_STATUS_ERR_NO_CHANNEL_ID);
goto out;
}
- id = silc_id_payload_parse_id(tmp, tmp_len);
+ id = silc_id_payload_parse_id(channel_id, channel_id_len);
/* If we are server and we don't know about this channel we will send
the command to our router. If we know about the channel then we also
/* Client's mode on channel */
SILC_PUT32_MSB(chl->mode, client_mode_list->data);
silc_buffer_pull(client_mode_list, 4);
+
+ list_count++;
}
silc_buffer_push(client_id_list,
client_id_list->data - client_id_list->head);
silc_buffer_push(client_mode_list,
client_mode_list->data - client_mode_list->head);
+ /* List count */
+ SILC_PUT32_MSB(list_count, lc);
+
/* Send reply */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_USERS,
SILC_STATUS_OK, 0, 4,
- 2, tmp, tmp_len,
- 3, client_id_list->data,
+ 2, channel_id, channel_id_len,
+ 3, lc, 4,
+ 4, client_id_list->data,
client_id_list->len,
- 4, client_mode_list->data,
+ 5, client_mode_list->data,
client_mode_list->len);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
}
}
- if (nickname && client->nickname) {
+ if (nickname && client->nickname)
silc_free(client->nickname);
+
+ if (nickname)
client->nickname = nick;
- }
if (username && client->username) {
silc_free(client->username);
/* We don't have that client anywhere, add it. The client is added
to global list since server didn't have it in the lists so it must be
global. */
- silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
- client_id, NULL, NULL);
+ client = silc_idlist_add_client(server->global_list, NULL, NULL,
+ NULL, client_id, cmd->sock->user_data,
+ NULL);
} else {
/* We have the client already. */
silc_free(client_id);
}
+
+ if (!silc_server_client_on_channel(client, channel)) {
+ /* Client was not on the channel, add it. */
+ SilcChannelClientEntry chl = silc_calloc(1, sizeof(*chl));
+ chl->client = client;
+ chl->mode = mode;
+ chl->channel = channel;
+ silc_list_add(channel->user_list, chl);
+ silc_list_add(client->channels, chl);
+ }
}
silc_buffer_free(client_id_list);
we will broadcast it. The sending socket really cannot be router or
the router is buggy. If this packet is coming from router then it must
have the broadcast flag set already and we won't do anything. */
- if (server->server_type == SILC_ROUTER &&
+ if (!server->standalone && server->server_type == SILC_ROUTER &&
sock->type == SILC_SOCKET_TYPE_SERVER &&
!(packet->flags & SILC_PACKET_FLAG_BROADCAST)) {
SILC_LOG_DEBUG(("Broadcasting received Replace ID packet"));
continue;
}
- if (server->server_type == SILC_ROUTER && !route)
- continue;
-
- if (server->server_type == SILC_SERVER && client->router)
+ if (client && client->router)
continue;
/* Send to locally connected client */
/* XXX must take some info to history before freeing */
/* Send REMOVE_ID packet to routers. */
- silc_server_send_remove_id(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE, user_data->id,
- SILC_ID_CLIENT_LEN, SILC_ID_CLIENT);
+ if (!server->standalone)
+ silc_server_send_remove_id(server, server->router->connection,
+ server->server_type == SILC_SERVER ?
+ FALSE : TRUE, user_data->id,
+ SILC_ID_CLIENT_LEN, SILC_ID_CLIENT);
/* Free the client entry and everything in it */
silc_idlist_del_data(user_data);
Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
[ServerInfo]
-lassi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
+lassi.kuo.fi.ssh.com:212.146.8.246:Kuopio, Finland:1334
[ListenPort]
-10.2.1.7:10.2.1.7:1334
+212.146.8.246:212.146.8.246:1334
[Logging]
infologfile:silcd2.log:10000
[AdminConnection]
[ServerConnection]
-10.2.1.7:passwd:priikone:1333:1:1
+212.146.8.246:passwd:priikone:1333:1:1
[RouterConnection]
-10.2.1.7:passwd:priikone:1335:1:1:0
+212.146.8.246:passwd:priikone:1335:1:1:0
[DenyConnection]
[RedirectClient]
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
SilcIDCacheEntry id_cache = NULL;
+ SilcChannelEntry channel;
SilcBuffer buffer, idp;
char *name;
goto out;
}
- /* Send USERS command to the server */
- idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
- buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 0, 1,
- 1, idp->data, idp->len);
- silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
- 0, NULL, NULL, buffer->data, buffer->len, TRUE);
- silc_buffer_free(buffer);
- silc_buffer_free(idp);
+ channel = (SilcChannelEntry)id_cache->context;
+
+ if (!cmd->pending) {
+ /* Send USERS command to the server */
+ idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_USERS, 0, 1,
+ 1, idp->data, idp->len);
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL, buffer->data,
+ buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(idp);
+
+ /* Register pending callback which will recall this command callback with
+ same context and reprocesses the command. When reprocessing we actually
+ display the information on the screen. */
+ silc_client_command_pending(conn, SILC_COMMAND_USERS, 0,
+ silc_client_command_users, context);
+ cmd->pending = TRUE;
+ return;
+ }
+
+ if (cmd->pending) {
+ /* Pending command. Now we've resolved the information from server and
+ we are ready to display the information on screen. */
+ int i;
+ SilcChannelUser chu;
+
+ cmd->client->ops->say(cmd->client, conn, "Users on %s",
+ channel->channel_name);
- /* Register dummy pending command that will tell the reply command
- that user called this command. Server may send reply to this command
- even if user did not send this command thus we want to handle things
- differently when user sent the command. This is dummy and won't be
- executed. */
- /* XXX this is kludge and should be removed after pending command reply
- support is added. Currently only commands may be pending not command
- replies. */
- silc_client_command_pending(conn, SILC_COMMAND_USERS, 0,
- silc_client_command_users, NULL);
+ silc_list_start(channel->clients);
+ while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
+ SilcClientEntry e = chu->client;
+ char *m, tmp[80], line[80], len1;
+
+ memset(line, 0, sizeof(line));
+ memset(tmp, 0, sizeof(tmp));
+ m = silc_client_chumode_char(chu->mode);
+
+ strcat(line, " ");
+ strcat(line, e->nickname);
+ strcat(line, e->server ? "@" : "");
+
+ len1 = 0;
+ if (e->server)
+ len1 = strlen(e->server);
+ strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
+
+ len1 = strlen(line);
+ if (len1 >= 30) {
+ memset(&line[29], 0, len1 - 29);
+ } else {
+ for (i = 0; i < 30 - len1 - 1; i++)
+ strcat(line, " ");
+ }
+
+ strcat(line, " H");
+ strcat(tmp, m ? m : "");
+ strcat(line, tmp);
+
+ if (strlen(tmp) < 5)
+ for (i = 0; i < 5 - strlen(tmp); i++)
+ strcat(line, " ");
+
+ strcat(line, e->username ? e->username : "");
+
+ cmd->client->ops->say(cmd->client, conn, "%s", line);
+
+ if (m)
+ silc_free(m);
+ }
+ }
/* Notify application */
COMMAND;
unsigned char **argv;
unsigned int *argv_lens;
unsigned int *argv_types;
+ int pending; /* Command is being re-processed when TRUE */
} *SilcClientCommandContext;
/* Structure holding pending commands. If command is pending it will be
executed after command reply has been executed. */
-/* XXX This support may added for commands as well and not just command
- replies, if needed later. */
typedef struct SilcClientCommandPendingStruct {
SilcCommand reply_cmd;
SilcCommandCb callback;
SILC_GET16_MSB(idp_len, client_id_list->data + 2);
idp_len += 4;
client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
- silc_buffer_pull(client_id_list, idp_len);
/* Mode */
SILC_GET32_MSB(mode, client_mode_list->data);
- silc_buffer_pull(client_mode_list, 4);
/* Check if we have this client cached already. */
if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
silc_free(client_id);
id_cache = NULL;
}
+
+ silc_buffer_pull(client_id_list, idp_len);
+ silc_buffer_pull(client_mode_list, 4);
}
/* Query the client information from server if the list included clients
/* We have all the clients on the channel cached now. Create a nice
output for user interface and notify application. */
- if (cmd->callback) {
- /* User has called USERS command on user interface. */
- cmd->client->ops->say(cmd->client, conn, "Users on %s",
- channel->channel_name);
-
- silc_list_start(channel->clients);
- while ((chu = silc_list_get(channel->clients)) != SILC_LIST_END) {
- SilcClientEntry e = chu->client;
- char *m, tmp[80], line[80], len1;
-
- memset(line, 0, sizeof(line));
- memset(tmp, 0, sizeof(tmp));
- m = silc_client_chumode_char(chu->mode);
-
- strcat(line, " ");
- strcat(line, e->nickname);
- strcat(line, e->server ? "@" : "");
-
- len1 = 0;
- if (e->server)
- len1 = strlen(e->server);
- strncat(line, e->server ? e->server : "", len1 > 30 ? 30 : len1);
-
- len1 = strlen(line);
- if (len1 >= 30) {
- memset(&line[29], 0, len1 - 29);
- } else {
- for (i = 0; i < 30 - len1 - 1; i++)
- strcat(line, " ");
- }
-
- strcat(line, " H");
- strcat(tmp, m ? m : "");
- strcat(line, tmp);
-
- if (strlen(tmp) < 5)
- for (i = 0; i < 5 - strlen(tmp); i++)
- strcat(line, " ");
-
- strcat(line, e->username ? e->username : "");
-
- cmd->client->ops->say(cmd->client, conn, "%s", line);
-
- if (m)
- silc_free(m);
- }
-
- } else {
+ if (!cmd->callback) {
/* Server has sent us USERS reply even when we haven't actually sent
USERS command. This is normal behaviour when joining to a channel.
Display some nice information on the user interface. */
} else {
SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, 1,
- 2, idp->data, idp->len);
+ 3, idp->data, idp->len);
return NULL;
}
}