From: Pekka Riikonen Date: Thu, 22 Mar 2001 09:13:48 +0000 (+0000) Subject: updates. X-Git-Tag: SILC.0.1~108 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=a14f8c2202a92454fac5e93f012672103a08ff0c updates. --- diff --git a/CHANGES b/CHANGES index dc17654a..3fd8b63d 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,28 @@ +Wed Mar 21 15:27:58 EET 2001 Pekka Riikonen + + * 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 [] 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 * The client entry's data.registered must be TRUE even with diff --git a/README b/README index 97e58a37..ac9e349f 100644 --- a/README +++ b/README @@ -43,10 +43,8 @@ To run SILC server ./silcd -f -Working Commands -================ - -Following commands has been, at least partly, implemented: +SILC Commands +============= /SERVER [[:]] @@ -92,7 +90,7 @@ Following commands has been, at least partly, implemented: Add client to/remove client from ban list I Add client to/remove client from invite list - c [:] + c Set/unset channel's cipher Multiple modes can be set/unset at once if the modes does not @@ -120,6 +118,14 @@ Following commands has been, at least partly, implemented: /UMODE +|- + 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 Sends private message to remote client. Support for @@ -201,6 +207,17 @@ Following commands has been, at least partly, implemented: Shutdowns the server. You must be server operator to be able to do this. + /MOTD [] + + Display the MOTD of the server. If server is not specified + the current server is used. + + /LIST [] + + Lists all channels in the current server, or the channel + specified. If the channel cannot be found then all + channels are listed. + Features ======== diff --git a/TODO b/TODO index 482f0055..b8bb37f6 100644 --- a/TODO +++ b/TODO @@ -102,13 +102,8 @@ TODO In SILC Server 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 @@ -119,7 +114,7 @@ TODO In SILC Server 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 diff --git a/apps/silc/client_ops.c b/apps/silc/client_ops.c index 0a9eb74d..690584b8 100644 --- a/apps/silc/client_ops.c +++ b/apps/silc/client_ops.c @@ -599,6 +599,55 @@ void silc_command_reply(SilcClient client, SilcClientConnection conn, } 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; diff --git a/apps/silcd/command.c b/apps/silcd/command.c index 7fac79e7..f92e8a39 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -561,7 +561,7 @@ silc_server_command_whois_send_reply(SilcServerCommandContext cmd, 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) @@ -1363,7 +1363,7 @@ silc_server_command_identify_send_reply(SilcServerCommandContext cmd, 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) @@ -1793,8 +1793,179 @@ SILC_SERVER_CMD_FUNC(nick) 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 @@ -2756,30 +2927,135 @@ SILC_SERVER_CMD_FUNC(motd) { 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: diff --git a/apps/silcd/command_reply.c b/apps/silcd/command_reply.c index 6dac16d1..b693e2f3 100644 --- a/apps/silcd/command_reply.c +++ b/apps/silcd/command_reply.c @@ -54,6 +54,7 @@ SilcServerCommandReply silc_command_reply_list[] = 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), @@ -187,7 +188,7 @@ silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd) /* 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); @@ -314,9 +315,8 @@ silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd) /* 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) @@ -435,7 +435,7 @@ silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd) /* 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; @@ -524,7 +524,7 @@ SILC_SERVER_CMD_REPLY_FUNC(info) 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; @@ -560,6 +560,53 @@ SILC_SERVER_CMD_REPLY_FUNC(info) 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. */ diff --git a/apps/silcd/command_reply.h b/apps/silcd/command_reply.h index 0726f108..397c825f 100644 --- a/apps/silcd/command_reply.h +++ b/apps/silcd/command_reply.h @@ -65,6 +65,7 @@ SILC_SERVER_CMD_REPLY_FUNC(whois); 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); diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 6d0b9030..b5c17daf 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -287,7 +287,8 @@ 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) { SilcClientEntry client; @@ -304,8 +305,7 @@ silc_idlist_add_client(SilcIDList id_list, unsigned char *nickname, 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); @@ -382,6 +382,10 @@ silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, /* 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, @@ -775,5 +779,42 @@ silc_idlist_replace_channel_id(SilcIDList id_list, SilcChannelID *old_id, 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; +} diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index 59d6282d..efca0dbf 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -107,6 +107,12 @@ typedef struct { 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 @@ -134,6 +140,7 @@ struct SilcServerEntryStruct { int server_type; SilcServerID *id; char *server_info; + char *motd; /* Pointer to the router */ SilcServerEntry router; @@ -489,7 +496,8 @@ silc_idlist_replace_server_id(SilcIDList id_list, SilcServerID *old_id, 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 * @@ -528,5 +536,8 @@ silc_idlist_find_channel_by_id(SilcIDList id_list, SilcChannelID *id, 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 diff --git a/apps/silcd/packet_receive.c b/apps/silcd/packet_receive.c index 98fb540b..16e9fa43 100644 --- a/apps/silcd/packet_receive.c +++ b/apps/silcd/packet_receive.c @@ -148,7 +148,7 @@ void silc_server_notify(SilcServer server, 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) { @@ -1305,8 +1305,9 @@ static void silc_server_new_id_real(SilcServer server, 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; diff --git a/apps/silcd/server.c b/apps/silcd/server.c index 999c24b6..6df25f7b 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -1184,7 +1184,7 @@ SILC_TASK_CALLBACK(silc_server_accept_new_connection_final) 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); @@ -3102,7 +3102,8 @@ void silc_server_save_users_on_channel(SilcServer server, /* 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) { diff --git a/apps/silcd/testi2.conf b/apps/silcd/testi2.conf index 7140f118..42ed3eae 100644 --- a/apps/silcd/testi2.conf +++ b/apps/silcd/testi2.conf @@ -1,23 +1,17 @@ [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] @@ -31,10 +25,10 @@ nobody:nobody 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 @@ -53,13 +47,16 @@ errorlogfile: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 diff --git a/doc/draft-riikonen-silc-spec-01.nroff b/doc/draft-riikonen-silc-spec-01.nroff index 8c238d8c..a80c2eea 100644 --- a/doc/draft-riikonen-silc-spec-01.nroff +++ b/doc/draft-riikonen-silc-spec-01.nroff @@ -2182,24 +2182,22 @@ List of all defined commands in SILC follows. 5 SILC_COMMAND_LIST - Max Arguments: 2 - Arguments: (1) [] [] + Max Arguments: 1 + Arguments: (1) [] - 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 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 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) (2) - (3) (4) + (3) (4) [] + (5) [] This command may reply with several command reply messages to form a list of results. In this case the status payload will include @@ -2219,8 +2217,8 @@ List of all defined commands in SILC follows. 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 @@ -2296,6 +2294,7 @@ List of all defined commands in SILC follows. 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 @@ -2570,8 +2569,9 @@ List of all defined commands in SILC follows. Reply messages to the command: - Max Arguments: 2 - Arguments: (1) (2) [] + Max Arguments: 3 + Arguments: (1) (2) + (3) [] This command replies with the motd message if it exists. diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 7c90c184..002363fb 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -407,8 +407,53 @@ SILC_CLIENT_CMD_FUNC(nick) 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. */ @@ -906,17 +951,22 @@ SILC_CLIENT_CMD_FUNC(motd) 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 []"); 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); diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 91579710..261578cf 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -592,8 +592,47 @@ SILC_CLIENT_CMD_REPLY_FUNC(nick) 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. */ @@ -1042,13 +1081,13 @@ SILC_CLIENT_CMD_REPLY_FUNC(motd) } 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; diff --git a/lib/silccore/silcnotify.h b/lib/silccore/silcnotify.h index 68faeed3..3b42fbaa 100644 --- a/lib/silccore/silcnotify.h +++ b/lib/silccore/silcnotify.h @@ -28,8 +28,7 @@ typedef struct SilcNotifyPayloadStruct *SilcNotifyPayload; 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" */