+Wed Mar 21 15:27:58 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Fixed MOTD command in the server to work in router environment.
+
+ * Fixed the MOTD command in the client library to support
+ the server argument in the command.
+
+ * Added `nickname_len' argument to the silc_idlist_add_client
+ in the server, as the `nickname' argument may be binary data
+ (it may be hash).
+
+ * Added silc_idlist_get_channels to return all channels from
+ the ID list.
+
+ * Implemented LIST command to the server. Affected file is
+ silcd/command.c.
+
+ * Implemented the LIST command to the client library and on the
+ user interface.
+
+ * Added [<user count>] argument to the LIST command reply.
+ With private channels the user count is not shown.
+
+ * Updated TODO and README.
+
Tue Mar 20 21:05:57 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* The client entry's data.registered must be TRUE even with
./silcd -f <config file>
-Working Commands
-================
-
-Following commands has been, at least partly, implemented:
+SILC Commands
+=============
/SERVER [<server>[:<port>]]
Add client to/remove client from ban list
I <username!nickname@server>
Add client to/remove client from invite list
- c <cipher>[:<keylen>]
+ c <cipher>
Set/unset channel's cipher
Multiple modes can be set/unset at once if the modes does not
/UMODE +|-<modes>
+ Sets/unsets user mode. Currently none of the modes can
+ be set by the user so this command can be merely used to
+ unset some mode. Following user modes are available:
+
+ a Unset all modes
+ s Unset server operator privileges
+ r Unset router operator privileges
+
/MSG <nickname> <message>
Sends private message to remote client. Support for
Shutdowns the server. You must be server operator to be
able to do this.
+ /MOTD [<server>]
+
+ Display the MOTD of the server. If server is not specified
+ the current server is used.
+
+ /LIST [<channel>]
+
+ Lists all channels in the current server, or the channel
+ specified. If the channel cannot be found then all
+ channels are listed.
+
Features
========
o TODO in command.c and in command_reply.c:
- o LIST is not implemented
o RESTART is not implemented
o INVITE is probably not working correctly
- o PING works only with local server. It must work with any
- server in the network, implement the sending to other servers.
- o MOTD works only with local server. It must work with any
- server in the network, implement the sending to other servers.
o JOIN does not check the invite and ban lists
o CMODE should be rewritten as it uses a lot duplicated code.
Some of the modes may still not be implemented or is implemented
it is not called but in server, I think, it must be called.
When implementing this check that all commands handle the
situation correctly when it is called as pending command
- (it should most likely the that cmd->pending == TRUE/FALSE).
+ (it should most likely check that cmd->pending == TRUE/FALSE).
o Packet processing can be made faster. All packet function in the
packet_receive.c has same prototypes. Instead of calling those from
}
break;
+ case SILC_COMMAND_LIST:
+ {
+ char *topic, *name;
+ unsigned int usercount;
+ unsigned char buf[256], tmp[16];
+ int i, len;
+
+ if (!success)
+ return;
+
+ (void)va_arg(vp, SilcChannelEntry);
+ name = va_arg(vp, char *);
+ topic = va_arg(vp, char *);
+ usercount = va_arg(vp, unsigned int);
+
+ if (status == SILC_STATUS_LIST_START ||
+ status == SILC_STATUS_OK)
+ silc_say(client, conn,
+ " Channel Users Topic");
+
+ memset(buf, 0, sizeof(buf));
+ strncat(buf, " ", 2);
+ len = strlen(name);
+ strncat(buf, name, len > 40 ? 40 : len);
+ if (len < 40)
+ for (i = 0; i < 40 - len; i++)
+ strcat(buf, " ");
+ strcat(buf, " ");
+
+ memset(tmp, 0, sizeof(tmp));
+ if (usercount) {
+ snprintf(tmp, sizeof(tmp), "%d", usercount);
+ strcat(buf, tmp);
+ }
+ len = strlen(tmp);
+ if (len < 10)
+ for (i = 0; i < 10 - len; i++)
+ strcat(buf, " ");
+ strcat(buf, " ");
+
+ if (topic) {
+ len = strlen(topic);
+ strncat(buf, topic, len);
+ }
+
+ silc_say(client, conn, "%s", buf);
+ }
+ break;
+
case SILC_COMMAND_UMODE:
{
unsigned int mode;
if (count && i - 1 == count)
break;
- if (clients_count > 2)
+ if (i >= 1)
status = SILC_STATUS_LIST_ITEM;
if (clients_count > 1 && i == clients_count - 1)
if (count && i - 1 == count)
break;
- if (clients_count > 2)
+ if (i >= 1)
status = SILC_STATUS_LIST_ITEM;
if (clients_count > 1 && i == clients_count - 1)
silc_server_command_free(cmd);
}
+/* Sends the LIST command reply */
+
+static void
+silc_server_command_list_send_reply(SilcServerCommandContext cmd,
+ SilcChannelEntry *lch,
+ unsigned int lch_count,
+ SilcChannelEntry *gch,
+ unsigned int gch_count)
+{
+ int i;
+ SilcBuffer packet, idp;
+ SilcChannelEntry entry;
+ SilcCommandStatus status;
+ unsigned short ident = silc_command_get_ident(cmd->payload);
+ char *topic;
+ unsigned char usercount[4];
+ unsigned int users;
+
+ for (i = 0; i < lch_count; i++)
+ if (lch[i]->mode & SILC_CHANNEL_MODE_SECRET)
+ lch[i] = NULL;
+ for (i = 0; i < gch_count; i++)
+ if (gch[i]->mode & SILC_CHANNEL_MODE_SECRET)
+ gch[i] = NULL;
+
+ status = SILC_STATUS_OK;
+ if ((lch_count + gch_count) > 1)
+ status = SILC_STATUS_LIST_START;
+
+ /* Local list */
+ for (i = 0; i < lch_count; i++) {
+ entry = lch[i];
+
+ if (!entry)
+ continue;
+
+ if (i >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+
+ if (i == lch_count - 1 && gch_count)
+ break;
+ if (lch_count > 1 && i == lch_count - 1)
+ status = SILC_STATUS_LIST_END;
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+
+ if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
+ topic = "*private*";
+ memset(usercount, 0, sizeof(usercount));
+ } else {
+ topic = entry->topic;
+ users = silc_list_count(entry->user_list);
+ SILC_PUT32_MSB(users, usercount);
+ }
+
+ /* Send the reply */
+ if (topic)
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name),
+ 4, topic, strlen(topic),
+ 5, usercount, 4);
+ else
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
+ status, ident, 3,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name),
+ 5, usercount, 4);
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0, packet->data,
+ packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ }
+
+ status = i ? SILC_STATUS_LIST_ITEM : SILC_STATUS_OK;
+
+ /* Global list */
+ for (i = 0; i < gch_count; i++) {
+ entry = gch[i];
+
+ if (!entry)
+ continue;
+
+ if (i >= 1)
+ status = SILC_STATUS_LIST_ITEM;
+
+ if (gch_count > 1 && i == lch_count - 1)
+ status = SILC_STATUS_LIST_END;
+
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CHANNEL);
+
+ if (entry->mode & SILC_CHANNEL_MODE_PRIVATE) {
+ topic = "*private*";
+ memset(usercount, 0, sizeof(usercount));
+ } else {
+ topic = entry->topic;
+ users = silc_list_count(entry->user_list);
+ SILC_PUT32_MSB(users, usercount);
+ }
+
+ /* Send the reply */
+ if (topic)
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
+ status, ident, 4,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name),
+ 4, topic, strlen(topic),
+ 5, usercount, 4);
+ else
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_LIST,
+ status, ident, 3,
+ 2, idp->data, idp->len,
+ 3, entry->channel_name,
+ strlen(entry->channel_name),
+ 5, usercount, 4);
+ silc_server_packet_send(cmd->server, cmd->sock,
+ SILC_PACKET_COMMAND_REPLY, 0, packet->data,
+ packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ }
+}
+
+/* Server side of LIST command. This lists the channel of the requested
+ server. Secret channels are not listed. */
+
SILC_SERVER_CMD_FUNC(list)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcChannelID *channel_id = NULL;
+ unsigned char *tmp;
+ unsigned int tmp_len;
+ SilcChannelEntry *lchannels = NULL, *gchannels = NULL;
+ unsigned int lch_count = 0, gch_count = 0;
+
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_LIST, cmd, 0, 2);
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (tmp) {
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_LIST,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ }
+
+ /* Get the channels from local list */
+ lchannels = silc_idlist_get_channels(server->local_list, channel_id,
+ &lch_count);
+
+ /* Get the channels from global list if we are router */
+ if (server->server_type == SILC_ROUTER)
+ gchannels = silc_idlist_get_channels(server->global_list, channel_id,
+ &gch_count);
+
+ /* Send the reply */
+ silc_server_command_list_send_reply(cmd, lchannels, lch_count,
+ gchannels, gch_count);
+
+ out:
+ silc_server_command_free(cmd);
}
/* Server side of TOPIC command. Sets topic for channel and/or returns
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- char *motd;
+ SilcBuffer packet, idp;
+ char *motd, *dest_server;
int motd_len;
+ unsigned short ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_MOTD, cmd, 1, 1);
- /* XXX show currently only our motd */
+ /* Get server name */
+ dest_server = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (!dest_server) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
- if (server->config && server->config->motd &&
- server->config->motd->motd_file) {
+ if (!strncasecmp(dest_server, server->server_name, strlen(dest_server))) {
+ /* Send our MOTD */
- /* Send motd */
- motd = silc_file_read(server->config->motd->motd_file, &motd_len);
- if (!motd)
+ idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
+
+ if (server->config && server->config->motd &&
+ server->config->motd->motd_file) {
+ /* Send motd */
+ motd = silc_file_read(server->config->motd->motd_file, &motd_len);
+ if (!motd)
+ goto out;
+
+ motd[motd_len] = 0;
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+ SILC_STATUS_OK, ident, 2,
+ 2, idp, idp->len,
+ 3, motd, motd_len);
goto out;
+ } else {
+ /* No motd */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+ SILC_STATUS_OK, ident, 1,
+ 2, idp, idp->len);
+ }
- motd[motd_len] = 0;
- silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD,
- SILC_STATUS_OK,
- 2, motd, motd_len);
- goto out;
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
} else {
- /* No motd */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD,
- SILC_STATUS_OK);
+ SilcServerEntry entry;
+
+ /* Check whether we have this server cached */
+ entry = silc_idlist_find_server_by_name(server->global_list,
+ dest_server, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_name(server->local_list,
+ dest_server, NULL);
+ }
+
+ if (server->server_type == SILC_ROUTER && !cmd->pending &&
+ entry && !entry->motd) {
+ /* Send to the server */
+ SilcBuffer tmpbuf;
+ unsigned short old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, entry->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_MOTD,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_motd,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ return;
+ }
+
+ if (!entry && !cmd->pending && !server->standalone) {
+ /* Send to the primary router */
+ SilcBuffer tmpbuf;
+ unsigned short old_ident;
+
+ old_ident = silc_command_get_ident(cmd->payload);
+ silc_command_set_ident(cmd->payload, silc_rng_get_rn16(server->rng));
+ tmpbuf = silc_command_payload_encode_payload(cmd->payload);
+
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_COMMAND, cmd->packet->flags,
+ tmpbuf->data, tmpbuf->len, TRUE);
+
+ /* Reprocess this packet after received reply from router */
+ silc_server_command_pending(server, SILC_COMMAND_MOTD,
+ silc_command_get_ident(cmd->payload),
+ silc_server_command_destructor,
+ silc_server_command_motd,
+ silc_server_command_dup(cmd));
+ cmd->pending = TRUE;
+ silc_command_set_ident(cmd->payload, old_ident);
+ silc_buffer_free(tmpbuf);
+ return;
+ }
+
+ if (!entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INFO,
+ SILC_STATUS_ERR_NO_SUCH_SERVER);
+ goto out;
+ }
+
+ idp = silc_id_payload_encode(server->id_entry->id, SILC_ID_SERVER);
+
+ if (entry->motd)
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+ SILC_STATUS_OK, ident, 2,
+ 2, idp, idp->len,
+ 3, entry->motd,
+ strlen(entry->motd));
+ else
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_MOTD,
+ SILC_STATUS_OK, ident, 1,
+ 2, idp, idp->len);
+
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ silc_buffer_free(idp);
}
out:
SILC_SERVER_CMD_REPLY(whowas, WHOWAS),
SILC_SERVER_CMD_REPLY(identify, IDENTIFY),
SILC_SERVER_CMD_REPLY(info, INFO),
+ SILC_SERVER_CMD_REPLY(motd, MOTD),
SILC_SERVER_CMD_REPLY(join, JOIN),
SILC_SERVER_CMD_REPLY(users, USERS),
/* 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. */
- client = silc_idlist_add_client(server->global_list, nick,
+ client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
strdup(username),
strdup(realname), client_id,
cmd->sock->user_data, NULL);
/* 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. */
- client = silc_idlist_add_client(server->global_list, nick,
- strdup(username),
- strdup(realname),
+ client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
+ strdup(username), strdup(realname),
silc_id_dup(client_id, SILC_ID_CLIENT),
cmd->sock->user_data, NULL);
if (!client)
/* 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. */
- client = silc_idlist_add_client(server->global_list, nick,
+ client = silc_idlist_add_client(server->global_list, nick, strlen(nick),
username ? strdup(username) : NULL, NULL,
client_id, cmd->sock->user_data, NULL);
client->data.registered = TRUE;
if (!server_id)
goto out;
- /* Get the info string */
+ /* Get the name */
name = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
if (tmp_len > 256)
goto out;
silc_server_command_reply_free(cmd);
}
+/* Received reply fro MOTD command. */
+
+SILC_SERVER_CMD_REPLY_FUNC(motd)
+{
+ SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
+ SilcServer server = cmd->server;
+ SilcCommandStatus status;
+ SilcServerEntry entry;
+ SilcServerID *server_id;
+ unsigned int tmp_len;
+ unsigned char *tmp;
+
+ COMMAND_CHECK_STATUS;
+
+ /* Get Server ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+ server_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!server_id)
+ goto out;
+
+ entry = silc_idlist_find_server_by_id(server->local_list, server_id, NULL);
+ if (!entry) {
+ entry = silc_idlist_find_server_by_id(server->global_list, server_id,
+ NULL);
+ if (!entry)
+ goto out;
+ }
+
+ /* Get the motd */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (tmp_len > 256)
+ tmp = NULL;
+
+ entry->motd = tmp;
+
+ /* Execute any pending commands */
+ SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_MOTD);
+
+ entry->motd = NULL;
+
+ out:
+ SILC_SERVER_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_MOTD);
+ silc_server_command_reply_free(cmd);
+}
+
/* Received reply for forwarded JOIN command. Router has created or joined
the client to the channel. We save some channel information locally
for future use. */
SILC_SERVER_CMD_REPLY_FUNC(whowas);
SILC_SERVER_CMD_REPLY_FUNC(identify);
SILC_SERVER_CMD_REPLY_FUNC(info);
+SILC_SERVER_CMD_REPLY_FUNC(motd);
SILC_SERVER_CMD_REPLY_FUNC(join);
SILC_SERVER_CMD_REPLY_FUNC(users);
SilcClientEntry
silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname,
- char *username, char *userinfo, SilcClientID *id,
+ unsigned int nickname_len, char *username,
+ char *userinfo, SilcClientID *id,
SilcServerEntry router, void *connection)
{
SilcClientEntry client;
silc_list_init(client->channels, struct SilcChannelClientEntryStruct,
client_list);
- if (!silc_idcache_add(id_list->clients, nickname,
- nickname ? strlen(nickname) : 0,
+ if (!silc_idcache_add(id_list->clients, nickname, nickname_len,
SILC_ID_CLIENT, (void *)client->id,
(void *)client, TRUE, FALSE)) {
silc_free(client);
/* Returns all clients matching requested nickname. Number of clients is
returned to `clients_count'. Caller must free the returned table. */
+/* XXX This actually checks the data, which can be hash of the nickname
+ but is not if the client is local client. Global client on global
+ list may have hash. Thus, this is not fully reliable function.
+ Instead this should probably check the hash from the lists client ID's. */
SilcClientEntry *
silc_idlist_get_clients_by_hash(SilcIDList id_list, char *nickname,
channel->id = new_id;
id_cache->id = (void *)new_id;
+ SILC_LOG_DEBUG(("Replaced"));
+
return channel;
}
+
+/* Returns channels from the ID list. If the `channel_id' is NULL then
+ all channels are returned. */
+
+SilcChannelEntry *
+silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
+ unsigned int *channels_count)
+{
+ SilcIDCacheList list = NULL;
+ SilcIDCacheEntry id_cache = NULL;
+ SilcChannelEntry *channels;
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ if (!silc_idcache_find_by_id(id_list->channels, channel_id ? channel_id :
+ SILC_ID_CACHE_ANY, SILC_ID_CHANNEL, &list))
+ return NULL;
+
+ channels = silc_calloc(silc_idcache_list_count(list), sizeof(*channels));
+
+ i = 0;
+ silc_idcache_list_first(list, &id_cache);
+ channels[i++] = (SilcChannelEntry)id_cache->context;
+
+ while (silc_idcache_list_next(list, &id_cache))
+ channels[i++] = (SilcChannelEntry)id_cache->context;
+
+ silc_idcache_list_free(list);
+
+ if (channels_count)
+ *channels_count = i;
+
+ return channels;
+}
the server SILC will ever need. These are also the informations
that is broadcasted between servers and routers in the SILC network.
+ char *server_info
+ char *motd
+
+ Server info (from INFO command) saved temporarily and motd (from
+ MOTD command) saved temporarily.
+
SilcServerEntry router
This is a pointer back to the server list. This is the router server
int server_type;
SilcServerID *id;
char *server_info;
+ char *motd;
/* Pointer to the router */
SilcServerEntry router;
void silc_idlist_del_server(SilcIDList id_list, SilcServerEntry entry);
SilcClientEntry
silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname,
- char *username, char *userinfo, SilcClientID *id,
+ unsigned int nickname_len, char *username,
+ char *userinfo, SilcClientID *id,
SilcServerEntry router, void *connection);
int silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry);
SilcClientEntry *
SilcChannelEntry
silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id,
SilcChannelID *new_id);
+SilcChannelEntry *
+silc_idlist_get_channels(SilcIDList id_list, SilcChannelID *channel_id,
+ unsigned int *channels_count);
#endif
goto out;
client =
- silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
+ silc_idlist_add_client(server->global_list, NULL, 0, NULL, NULL,
silc_id_dup(client_id, SILC_ID_CLIENT),
sock->user_data, NULL);
if (!client) {
sizeof(unsigned char));
memcpy(hash, ((SilcClientID *)id)->hash,
sizeof(((SilcClientID *)id)->hash));
- entry = silc_idlist_add_client(id_list, hash, NULL, NULL, id,
- router, NULL);
+ entry = silc_idlist_add_client(id_list, hash,
+ sizeof(((SilcClientID *)id)->hash),
+ NULL, NULL, id, router, NULL);
entry->nickname = NULL;
entry->data.registered = TRUE;
and other information is created after we have received NEW_CLIENT
packet from client. */
client = silc_idlist_add_client(server->local_list,
- NULL, NULL, NULL, NULL, NULL, sock);
+ NULL, 0, NULL, NULL, NULL, NULL, sock);
if (!client) {
SILC_LOG_ERROR(("Could not add new client to cache"));
silc_free(sock->user_data);
/* 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. */
- client = silc_idlist_add_client(server->global_list, NULL, NULL, NULL,
+ client = silc_idlist_add_client(server->global_list, NULL, 0, NULL,
+ NULL,
silc_id_dup(client_id, SILC_ID_CLIENT),
sock->user_data, NULL);
if (!client) {
[Cipher]
-aes-256-cbc:../lib/silcsim/modules/aes.sim.so:32:16
-aes-192-cbc:../lib/silcsim/modules/aes.sim.so:24:16
-aes-128-cbc:../lib/silcsim/modules/aes.sim.so:16:16
-twofish-256-cbc:../lib/silcsim/modules/twofish.sim.so:32:16
-twofish-192-cbc:../lib/silcsim/modules/twofish.sim.so:24:16
-twofish-128-cbc:../lib/silcsim/modules/twofish.sim.so:16:16
-mars-256-cbc:../lib/silcsim/modules/mars.sim.so:32:16
-mars-192-cbc:../lib/silcsim/modules/mars.sim.so:24:16
-mars-128-cbc:../lib/silcsim/modules/mars.sim.so:16:16
+rc6:../lib/silcsim/modules/rc6.sim.so:16:16
+twofish:../lib/silcsim/modules/twofish.sim.so:16:16
+mars:../lib/silcsim/modules/mars.sim.so:16:16
none:../lib/silcsim/modules/none.sim.so:0:0
-[Hash]
+[Hash]
md5::64:16
sha1::64:20
[hmac]
hmac-sha1-96:sha1:12
hmac-md5-96:md5:12
-hmac-sha1:sha1:20
+hmac-sha1:sha1:20
hmac-md5:md5:16
#[PKCS]
Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
[ServerInfo]
-silc:212.146.42.253:Kuopio, Finland:1334
+lassi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
[ListenPort]
-212.146.42.253:212.146.42.253:1334
+10.2.1.7:10.2.1.7:1334
[Logging]
infologfile:silcd2.log:10000
:::1336:1
[AdminConnection]
-*:priikone:*:passwd:testi
+*:silc:silc:passwd:testi
[ServerConnection]
-212.146.42.253:passwd:priikone:1336:1:1
+10.2.1.7:passwd:priikone:1333:1:1
[RouterConnection]
-212.146.42.253:passwd:priikone:1335:1:1:0
+10.2.1.7:passwd:priikone:1335:1:1:0
[DenyConnection]
[RedirectClient]
+
+[motd]
+./motd
5 SILC_COMMAND_LIST
- Max Arguments: 2
- Arguments: (1) [<Channel ID>] [<server>]
+ Max Arguments: 1
+ Arguments: (1) [<Channel ID>]
- The list command is used to list channels and their topics on
+ The list command is used to list channels and their topics on the
current server. If the <Channel ID> parameter is used, only the
status of that channel is displayed. Secret channels are not
listed at all. Private channels are listed with status indicating
- that the channel is private.
-
- If the <server> argument is specified the specified server's
- channels are listed. In this case the command must be sent to
- the server who owns the channel that was requested.
+ that the channel is private. Router may reply with all channels
+ it knows about.
Reply messages to the command:
- Max Arguments: 4
+ Max Arguments: 5
Arguments: (1) <Status Payload> (2) <Channel ID>
- (3) <channel> (4) <topic>
+ (3) <channel> (4) [<topic>]
+ (5) [<user count>]
This command may reply with several command reply messages to form
a list of results. In this case the status payload will include
SILC_STATUS_ERR_WILDCARDS
SILC_STATUS_ERR_NOT_REGISTERED
SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SUCH_CHANNEL
SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+ SILC_STATUS_ERR_NO_CHANNEL_ID
SILC_STATUS_ERR_NO_SUCH_SERVER
SILC_STATUS_ERR_NO_CHANNEL_ID
SILC_STATUS_ERR_NOT_ON_CHANNEL
SILC_STATUS_ERR_USER_ON_CHANNEL
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV
8 SILC_COMMAND_QUIT
Reply messages to the command:
- Max Arguments: 2
- Arguments: (1) <Status Payload> (2) [<motd>]
+ Max Arguments: 3
+ Arguments: (1) <Status Payload> (2) <Server ID>
+ (3) [<motd>]
This command replies with the motd message if it exists.
silc_client_command_free(cmd);
}
+/* Command LIST. Lists channels on the current server. */
+
SILC_CLIENT_CMD_FUNC(list)
{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcIDCacheEntry id_cache = NULL;
+ SilcChannelEntry channel;
+ SilcBuffer buffer, idp = NULL;
+ char *name;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argc == 2) {
+ name = cmd->argv[1];
+
+ /* Get the Channel ID of the channel */
+ if (silc_idcache_find_by_data_one(conn->channel_cache, name, &id_cache)) {
+ channel = (SilcChannelEntry)id_cache->context;
+ idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
+ }
+ }
+
+ if (!idp)
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
+ ++conn->cmd_ident, 0);
+ else
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_LIST,
+ ++conn->cmd_ident, 1,
+ 1, idp->data, idp->len);
+
+ silc_client_packet_send(cmd->client, cmd->conn->sock,
+ SILC_PACKET_COMMAND, NULL, 0, NULL, NULL,
+ buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ if (idp)
+ silc_buffer_free(idp);
+
+ /* Notify application */
+ COMMAND;
+
+ out:
+ silc_client_command_free(cmd);
}
/* Command TOPIC. Sets/shows topic on a channel. */
goto out;
}
- if (cmd->argc < 1 || cmd->argc > 1) {
+ if (cmd->argc < 1 || cmd->argc > 2) {
cmd->client->ops->say(cmd->client, conn,
- "Usage: /MOTD");
+ "Usage: /MOTD [<server>]");
COMMAND_ERROR;
goto out;
}
/* Send TOPIC command to the server */
- buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
- 2, conn->remote_host,
- strlen(conn->remote_host));
+ if (cmd->argc == 1)
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
+ 1, conn->remote_host,
+ strlen(conn->remote_host));
+ else
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_MOTD, 0, 1,
+ 1, cmd->argv[1],
+ cmd->argv_lens[1]);
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_client_command_reply_free(cmd);
}
+/* Received reply to the LIST command. */
+
SILC_CLIENT_CMD_REPLY_FUNC(list)
{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcCommandStatus status;
+ unsigned char *tmp, *name, *topic;
+ unsigned int usercount = 0;
+
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ SILC_GET16_MSB(status, tmp);
+ if (status != SILC_STATUS_OK &&
+ status != SILC_STATUS_LIST_START &&
+ status != SILC_STATUS_LIST_ITEM &&
+ status != SILC_STATUS_LIST_END) {
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ name = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ topic = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
+ if (tmp)
+ SILC_GET32_MSB(usercount, tmp);
+
+ /* Notify application */
+ COMMAND_REPLY((ARGS, NULL, name, topic, usercount));
+
+ /* Pending callbacks are not executed if this was an list entry */
+ if (status != SILC_STATUS_OK &&
+ status != SILC_STATUS_LIST_END) {
+ silc_client_command_reply_free(cmd);
+ return;
+ }
+
+ /* Execute any pending command callbacks */
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LIST);
+
+ out:
+ SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_LIST);
+ silc_client_command_reply_free(cmd);
}
/* Received reply to topic command. */
}
argc = silc_argument_get_arg_num(cmd->args);
- if (argc > 2) {
+ if (argc > 3) {
COMMAND_REPLY_ERROR;
goto out;
}
- if (argc == 2) {
- motd = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (argc == 3) {
+ motd = silc_argument_get_arg_type(cmd->args, 3, NULL);
if (!motd) {
COMMAND_REPLY_ERROR;
goto out;
typedef unsigned short SilcNotifyType;
/* SILC notify types. Server may send these notify types to client to
- notify of some action. Server also sends human readable notify message
- to the client which client may ignore. */
+ notify of some action. */
#define SILC_NOTIFY_TYPE_NONE 0 /* no specific type */
#define SILC_NOTIFY_TYPE_INVITE 1 /* "invites you to channel" */
#define SILC_NOTIFY_TYPE_JOIN 2 /* "has joined channel" */