From 5569a5568cae381a4da5d5d1919fde1e29e5632b Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Fri, 6 Oct 2000 08:10:23 +0000 Subject: [PATCH] Added WHOIS to send multiple replies if multiple nicknames are found. Added MOTD command and [motd] config section and server also sends motd to client on connection now. Fixed TOPIC command some more. --- apps/silcd/command.c | 225 ++++++++++++++++++++++++++------------ apps/silcd/idlist.c | 39 +++++++ apps/silcd/idlist.h | 3 + apps/silcd/server.c | 43 +++++++- apps/silcd/server.h | 2 + apps/silcd/serverconfig.c | 24 ++++ apps/silcd/serverconfig.h | 7 ++ 7 files changed, 273 insertions(+), 70 deletions(-) diff --git a/apps/silcd/command.c b/apps/silcd/command.c index ca16cf73..c03fe0f1 100644 --- a/apps/silcd/command.c +++ b/apps/silcd/command.c @@ -293,10 +293,12 @@ SILC_SERVER_CMD_FUNC(whois) SilcServerCommandContext cmd = (SilcServerCommandContext)context; SilcServer server = cmd->server; char *tmp, *nick = NULL, *server_name = NULL; - unsigned int argc, count = 0, len; + unsigned int i, argc, count = 0, len, clients_count; SilcClientEntry entry; SilcBuffer packet; unsigned char *id_string; + SilcClientEntry *clients; + SilcCommandStatus status; SILC_LOG_DEBUG(("Start")); @@ -345,10 +347,11 @@ SILC_SERVER_CMD_FUNC(whois) count = atoi(tmp); } - /* Then, make the query from our local client list */ - entry = silc_idlist_find_client_by_nickname(server->local_list, - nick, server_name); - if (!entry) { + /* Get all clients matching that nickname */ + clients = silc_idlist_get_clients_by_nickname(server->local_list, + nick, server_name, + &clients_count); + if (!clients) { /* If we are normal server and are connected to a router we will make global query from the router. */ @@ -380,70 +383,88 @@ SILC_SERVER_CMD_FUNC(whois) ok: /* XXX, works only for local server info */ - /* Send WHOIS reply */ - id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT); - tmp = silc_command_get_first_arg(cmd->payload, NULL); - /* XXX */ - if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) { - char nh[256], uh[256]; - unsigned char idle[4]; - SilcSocketConnection hsock; + status = SILC_STATUS_OK; + if (clients_count > 1) + status = SILC_STATUS_LIST_START; - memset(uh, 0, sizeof(uh)); - memset(nh, 0, sizeof(nh)); + for (i = 0; i < clients_count; i++) { + entry = clients[i]; - strncat(nh, entry->nickname, strlen(entry->nickname)); - strncat(nh, "@", 1); - len = entry->router ? strlen(entry->router->server_name) : - strlen(server->server_name); - strncat(nh, entry->router ? entry->router->server_name : - server->server_name, len); + if (count && i - 1 == count) + break; - strncat(uh, entry->username, strlen(entry->username)); - strncat(uh, "@", 1); - hsock = (SilcSocketConnection)entry->connection; - len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip); - strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len); + if (clients_count > 2) + status = SILC_STATUS_LIST_ITEM; - SILC_PUT32_MSB((time(NULL) - entry->last_receive), idle); + if (clients_count > 1 && i == clients_count - 1) + status = SILC_STATUS_LIST_END; + /* Send WHOIS reply */ + id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT); + tmp = silc_command_get_first_arg(cmd->payload, NULL); + /* XXX */ - if (entry->userinfo) - packet = - silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS, - SILC_STATUS_OK, 5, - 2, id_string, SILC_ID_CLIENT_LEN, - 3, nh, strlen(nh), - 4, uh, strlen(uh), - 5, entry->userinfo, - strlen(entry->userinfo), - 7, idle, 4); - else + if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT) { + char nh[256], uh[256]; + unsigned char idle[4]; + SilcSocketConnection hsock; + + memset(uh, 0, sizeof(uh)); + memset(nh, 0, sizeof(nh)); + + strncat(nh, entry->nickname, strlen(entry->nickname)); + strncat(nh, "@", 1); + len = entry->router ? strlen(entry->router->server_name) : + strlen(server->server_name); + strncat(nh, entry->router ? entry->router->server_name : + server->server_name, len); + + strncat(uh, entry->username, strlen(entry->username)); + strncat(uh, "@", 1); + hsock = (SilcSocketConnection)entry->connection; + len = hsock->hostname ? strlen(hsock->hostname) : strlen(hsock->ip); + strncat(uh, hsock->hostname ? hsock->hostname : hsock->ip, len); + + SILC_PUT32_MSB((time(NULL) - entry->last_receive), idle); + + /* XXX */ + if (entry->userinfo) + packet = + silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS, + status, 5, + 2, id_string, SILC_ID_CLIENT_LEN, + 3, nh, strlen(nh), + 4, uh, strlen(uh), + 5, entry->userinfo, + strlen(entry->userinfo), + 7, idle, 4); + else + packet = + silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS, + status, 4, + 2, id_string, SILC_ID_CLIENT_LEN, + 3, nh, strlen(nh), + 4, uh, strlen(uh), + 7, idle, 4); + + } else { + /* XXX */ packet = - silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS, - SILC_STATUS_OK, 4, + silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS, + status, 3, 2, id_string, SILC_ID_CLIENT_LEN, - 3, nh, strlen(nh), - 4, uh, strlen(uh), - 7, idle, 4); - - } else { - /* XXX */ - packet = - silc_command_encode_reply_payload_va(SILC_COMMAND_WHOIS, - SILC_STATUS_OK, 3, - 2, id_string, SILC_ID_CLIENT_LEN, - 3, entry->nickname, - strlen(entry->nickname), - 4, tmp, strlen(tmp)); /* XXX */ - } - silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, - 0, packet->data, packet->len, FALSE); - - silc_free(id_string); - silc_buffer_free(packet); - + 3, entry->nickname, + strlen(entry->nickname), + 4, tmp, strlen(tmp)); /* XXX */ + } + silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, + 0, packet->data, packet->len, FALSE); + + silc_free(id_string); + silc_buffer_free(packet); + } + out: silc_server_command_free(cmd); } @@ -694,7 +715,8 @@ SILC_SERVER_CMD_FUNC(topic) SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data; SilcChannelID *channel_id; SilcChannelEntry channel; - unsigned char *tmp; + SilcBuffer packet; + unsigned char *tmp, *id_string; unsigned int argc; /* Check number of arguments */ @@ -719,6 +741,14 @@ SILC_SERVER_CMD_FUNC(topic) } channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL); + /* Check whether the channel exists */ + channel = silc_idlist_find_channel_by_id(server->local_list, channel_id); + if (!channel) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC, + SILC_STATUS_ERR_NO_SUCH_CHANNEL); + goto out; + } + if (argc > 1) { /* Get the topic */ tmp = silc_command_get_arg_type(cmd->payload, 2, NULL); @@ -728,15 +758,15 @@ SILC_SERVER_CMD_FUNC(topic) goto out; } - /* Check whether the channel exists */ - channel = silc_idlist_find_channel_by_id(server->local_list, channel_id); - if (!channel) { + if (strlen(tmp) > 256) { silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC, - SILC_STATUS_ERR_NO_SUCH_CHANNEL); + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); goto out; } /* Set the topic for channel */ + if (channel->topic) + silc_free(channel->topic); channel->topic = strdup(tmp); /* Send notify about topic change to all clients on the channel */ @@ -750,9 +780,25 @@ SILC_SERVER_CMD_FUNC(topic) } /* Send the topic to client as reply packet */ - silc_server_command_send_status_data(cmd, SILC_COMMAND_TOPIC, - SILC_STATUS_OK, - 2, tmp, strlen(tmp)); + id_string = silc_id_id2str(channel_id, SILC_ID_CHANNEL); + if (channel->topic) + packet = silc_command_encode_reply_payload_va(SILC_COMMAND_TOPIC, + SILC_STATUS_OK, 2, + 2, id_string, + SILC_ID_CHANNEL_LEN, + 3, channel->topic, + strlen(channel->topic)); + else + packet = silc_command_encode_reply_payload_va(SILC_COMMAND_TOPIC, + SILC_STATUS_OK, 1, + 2, id_string, + SILC_ID_CHANNEL_LEN); + silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY, + 0, packet->data, packet->len, FALSE); + + silc_free(id_string); + silc_buffer_free(packet); + silc_free(channel_id); out: silc_server_command_free(cmd); @@ -1324,9 +1370,50 @@ SILC_SERVER_CMD_FUNC(join) SILC_SERVER_CMD_FUNC(motd) { - + SilcServerCommandContext cmd = (SilcServerCommandContext)context; + SilcServer server = cmd->server; + SilcSocketConnection sock = cmd->sock; + unsigned int argc; + char *motd; + int motd_len; + SILC_LOG_DEBUG(("Start")); + argc = silc_command_get_arg_num(cmd->payload); + if (argc < 1) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE, + SILC_STATUS_ERR_NOT_ENOUGH_PARAMS); + goto out; + } + if (argc > 2) { + silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE, + SILC_STATUS_ERR_TOO_MANY_PARAMS); + goto out; + } + + /* XXX show currently only our motd */ + + 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; + silc_server_command_send_status_data(cmd, SILC_COMMAND_MOTD, + SILC_STATUS_OK, + 2, motd, motd_len); + goto out; + } else { + /* No motd */ + silc_server_command_send_status_reply(cmd, SILC_COMMAND_MOTD, + SILC_STATUS_OK); + } + + out: + silc_server_command_free(cmd); } SILC_SERVER_CMD_FUNC(umode) diff --git a/apps/silcd/idlist.c b/apps/silcd/idlist.c index 97ee8854..1df174e4 100644 --- a/apps/silcd/idlist.c +++ b/apps/silcd/idlist.c @@ -20,6 +20,13 @@ /* * $Id$ * $Log$ + * Revision 1.8 2000/10/06 08:10:23 priikone + * Added WHOIS to send multiple replies if multiple nicknames are + * found. + * Added MOTD command and [motd] config section and server also sends + * motd to client on connection now. + * Fixed TOPIC command some more. + * * Revision 1.7 2000/07/26 07:04:01 priikone * Added server_find_by_id, replace_[server/client]_id. * @@ -219,6 +226,38 @@ void silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry) } } +/* Returns all clients matching requested nickname. Number of clients is + returned to `clients_count'. Caller must free the returned table. */ + +SilcClientEntry * +silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, + char *server, unsigned int *clients_count) +{ + SilcIDCacheList list = NULL; + SilcIDCacheEntry id_cache = NULL; + SilcClientEntry *clients; + int i; + + if (!silc_idcache_find_by_data(id_list->clients, nickname, &list)) + return NULL; + + clients = silc_calloc(silc_idcache_list_count(list), sizeof(*clients)); + + i = 0; + silc_idcache_list_first(list, &id_cache); + clients[i++] = (SilcClientEntry)id_cache->context; + + while (silc_idcache_list_next(list, &id_cache)) + clients[i++] = (SilcClientEntry)id_cache->context; + + silc_idcache_list_free(list); + + if (clients_count) + *clients_count = i; + + return clients; +} + /* Finds client entry by nickname. */ SilcClientEntry diff --git a/apps/silcd/idlist.h b/apps/silcd/idlist.h index e1f39ec1..6a40147f 100644 --- a/apps/silcd/idlist.h +++ b/apps/silcd/idlist.h @@ -442,6 +442,9 @@ silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username, SilcPKCS pkcs, SilcHmac hmac, SilcPublicKey public_key, void *connection); void silc_idlist_del_client(SilcIDList id_list, SilcClientEntry entry); +SilcClientEntry * +silc_idlist_get_clients_by_nickname(SilcIDList id_list, char *nickname, + char *server, unsigned int *clients_count); SilcClientEntry silc_idlist_find_client_by_nickname(SilcIDList id_list, char *nickname, char *server); diff --git a/apps/silcd/server.c b/apps/silcd/server.c index e735125f..f17de4f6 100644 --- a/apps/silcd/server.c +++ b/apps/silcd/server.c @@ -2643,6 +2643,46 @@ void silc_server_channel_key(SilcServer server, silc_buffer_free(buffer); } +/* Sends current motd to client */ + +void silc_server_send_motd(SilcServer server, + SilcSocketConnection sock) +{ + char *motd, *cp; + char line[256]; + int i, motd_len; + + if (server->config && server->config->motd && + server->config->motd->motd_file) { + + motd = silc_file_read(server->config->motd->motd_file, &motd_len); + if (!motd) + return; + + /* Send motd */ + i = 0; + cp = motd; + while(cp[i] != 0) { + if (cp[i++] == '\n') { + memset(line, 0, sizeof(line)); + strncat(line, cp, i - 1); + cp += i; + + if (i == 2) + line[0] = ' '; + + silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_NONE, line); + + if (!strlen(cp)) + break; + i = 0; + } + } + + silc_free(motd); + } +} + /* Sends error message. Error messages may or may not have any implications. */ @@ -3114,7 +3154,8 @@ SilcClientEntry silc_server_new_client(SilcServer server, "Your current nickname is %s", client->nickname); - /* XXX Send motd */ + /* Send motd */ + silc_server_send_motd(server, sock); return client; } diff --git a/apps/silcd/server.h b/apps/silcd/server.h index ae846d42..ef80e69e 100644 --- a/apps/silcd/server.h +++ b/apps/silcd/server.h @@ -113,6 +113,8 @@ void silc_server_channel_message(SilcServer server, void silc_server_channel_key(SilcServer server, SilcSocketConnection sock, SilcPacketContext *packet); +void silc_server_send_motd(SilcServer server, + SilcSocketConnection sock); void silc_server_send_error(SilcServer server, SilcSocketConnection sock, const char *fmt, ...); diff --git a/apps/silcd/serverconfig.c b/apps/silcd/serverconfig.c index b6d44d6b..fc89bace 100644 --- a/apps/silcd/serverconfig.c +++ b/apps/silcd/serverconfig.c @@ -20,6 +20,13 @@ /* * $Id$ * $Log$ + * Revision 1.4 2000/10/06 08:10:23 priikone + * Added WHOIS to send multiple replies if multiple nicknames are + * found. + * Added MOTD command and [motd] config section and server also sends + * motd to client on connection now. + * Fixed TOPIC command some more. + * * Revision 1.3 2000/07/10 05:41:20 priikone * Added missing token to administrative information. * @@ -189,6 +196,8 @@ SilcConfigServerSection silc_config_server_sections[] = { SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, 4 }, { "[RedirectClient]", SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT, 2 }, + { "[motd]", + SILC_CONFIG_SERVER_SECTION_TYPE_MOTD, 1 }, { NULL, SILC_CONFIG_SERVER_SECTION_TYPE_NONE, 0 } }; @@ -249,6 +258,7 @@ void silc_config_server_free(SilcConfigServer config) silc_free(config->routers); silc_free(config->denied); silc_free(config->redirect); + silc_free(config->motd); silc_free(config); } } @@ -980,6 +990,20 @@ int silc_config_server_parse_lines(SilcConfigServer config, check = TRUE; break; + case SILC_CONFIG_SERVER_SECTION_TYPE_MOTD: + + if (!config->motd) + config->motd = silc_calloc(1, sizeof(*config->motd)); + + /* Get motd file */ + ret = silc_config_get_token(line, &config->motd->motd_file); + if (ret < 0) + break; + + check = TRUE; + checkmask |= (1L << pc->section->type); + break; + case SILC_CONFIG_SERVER_SECTION_TYPE_NONE: default: /* Error */ diff --git a/apps/silcd/serverconfig.h b/apps/silcd/serverconfig.h index af017597..5b7a1d54 100644 --- a/apps/silcd/serverconfig.h +++ b/apps/silcd/serverconfig.h @@ -133,6 +133,11 @@ typedef struct { unsigned short port; } SilcConfigServerSectionRedirectClient; +/* Holds motd file */ +typedef struct { + char *motd_file; +} SilcConfigServerSectionMotd; + /* SILC Server Config object. @@ -162,6 +167,7 @@ typedef struct { SilcConfigServerSectionAdminConnection *admins; SilcConfigServerSectionDenyConnection *denied; SilcConfigServerSectionRedirectClient *redirect; + SilcConfigServerSectionMotd *motd; } SilcConfigServerObject; typedef SilcConfigServerObject *SilcConfigServer; @@ -183,6 +189,7 @@ typedef enum { SILC_CONFIG_SERVER_SECTION_TYPE_ADMIN_CONNECTION, SILC_CONFIG_SERVER_SECTION_TYPE_DENY_CONNECTION, SILC_CONFIG_SERVER_SECTION_TYPE_REDIRECT_CLIENT, + SILC_CONFIG_SERVER_SECTION_TYPE_MOTD, } SilcConfigServerSectionType; /* SILC Configuration Section structure. */ -- 2.24.0