TODO list, see CHANGES.
+Wed Apr 3 16:24:51 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Upgraded the protocol version to 1.1, updated protocol specs
+ and software.
+
+ * Added the nickname as new argument to NICK_CHANGE notify and
+ added it to protocol specs and implemented it to client and
+ server. Protocol TODO #3. Affected files are silcd/idlist.[ch],
+ silcd/command.c, silcd/packet_receive.c, packet_send.[ch], and
+ lib/silcclient/client_notify.c.
+
+ * Added the killer's client ID to the KILLED notify and added
+ it to protocol specs and implemented it to client and server.
+ Protocol TODO #13. Affected files are silcd/command.c,
+ silcd/packet_receive.c, packet_send.[ch],
+ lib/silcclient/client_notify.c, irssi/src/silc/core/client_ops.c.
+ The killer's client entry is now returned to application in
+ the `notify' client operation.
+
+ * Fixed the Max Argument fields that had too large value set
+ in the protocol specs. Protocol TODO #14.
+
+ * Added the LEAVE command reply to return the ID of parted
+ channel. Updated protocol specs and implemented it to the
+ client and server. Protocol TODO #15. Affected files are
+ silcd/command.c, lib/silcclient/command_reply.c. The channel
+ entry is now returned to application in the `command_reply'
+ client operation.
+
+ * Rewrote the version SKE version checking in client libary
+ and in server to use the silc_parse_version_string. Affected
+ files are lib/silcclient/protocol.c, silcd/protocol.c.
+
+ * Added SILC_STATUS_ERR_NO_CHANNEL_FOPRIV error status to few
+ commands that was missing it, and updated protocol specs and
+ the server implementation. Protocol TODO #10. The affected
+ file is silcd/command.c.
+
+ * Defined new message flags SILC_MESSAGE_FLAG_REPLY to be
+ generic reply to a generic request (REQUEST flag), and
+ SILC_MESSAGE_FLAG_DATA to send any kind of data in a generic
+ way. A draft-riikonen-silc-flags-payloads-00.txt is written
+ to define the payload for DATA flag. Added the flags to
+ the implementation. Protocol TODO #9. Affected file is
+ lib/silccore/silcchannel.h.
+
+ Changed the client library to return the message length
+ to application as well in the channel_message and private_message
+ client operations. Affected files are
+ lib/silcclient/client_prvmsg, lib/silcclient/client_channel.c,
+ lib/silcclient/silcclient.h, irssi/src/silc/core/client_ops.c,
+ and lib/silcclient/client_ops_example.c.
+
+ * Added two new channel modes: SILC_CMODE_SILENCE_USERS
+ and SILC_CMODE_SILENCE_OPERS which can be used to moderate
+ the channel. Updated protocol specs and impelemented this
+ to client and server. Protocol TODO #6. Affected files are
+ silcd/packet_receive.c, server_util.c, lib/silcclient/command.c,
+ lib/silcclient/client_channel.c, lib/silccore/silcmode.h.
+
+ Added new options m and M to CMODE command in Irssi SILC
+ client to set these modes.
+
+ * Deprecated all administrative commands from SILC protocol
+ since they are highly implementation specific commands.
+ Updated protocol specs. Moved the old commands in
+ implementations to private range of command types. Affected
+ files are silcd/command.c, lib/silcclient/command.c and
+ lib/silcclient/command_reply.c. Protocol TODO #8.
+
+ * Fixed a bug in server where sending unknown command crashes
+ the server. Affected file silcd/command.c.
+
Wed Apr 3 09:57:47 CEST 2002 Pekka Riikonen <priikone@silcnet.org>
* Added SILC_PROTOCOLVERSION macro to check protocol version
o Additions to do after protocol version 1.1:
- o Fix the NICK_CHANGE notify handling not to create new entry
- for the changed client, but take the nickname from the notify
- (removes need for resolving as well). Protocol TODO entry 3.
-
o Add support for list of errors in command replies. Protocol
TODO entry 1.
o JOIN (check that joining is allowed)
o SIGNOFF (maybe should check that notifier owns the client)
- o KILLED (check that killling is allowed (Protocol TODO #13))
o Backup router related issues (Fix this to 1.0):
*after* sending successfully found entries (this way receiver may
ignore them). To be included in protocol version 1.1.
- 3. Define the NICK_CHANGE notify to send the changed nickname as a new
- third argument. This will make the NICK_CHANGE notify handling easier
- in the receiver's end (client primarily) since it removes the
- requirement that receiver must resolve (using IDENTIFY or WHOIS) the
- new Client ID received in the notify (because of the new nickname is
- unknown). To be included in protocol version 1.1.
-
4. Add "request parameters" or similar to the WHOIS command, which can
be used to request various parameters (something not returned by
standard WHOIS command) about clients (info that could be fetched
5. Inviting and banning by public key should be made possible. To be
included in protocol version 1.x.
- 6. Add perhaps SILENCE_USERS, SILENCE_OPERS channel user modes which
- can be used to silence (moderate) normal users and opers (this set
- only by founder). To be included in protocol version 1.1.
-
7. Channel Message Payload needs slight redesining to include the IV
field to the MAC generation of the payload. It is authenticated
by the packet's MAC but not by the payload's MAC. Since the IV
payload MAC and not alone by packet MAC. To be included in protocol
version 1.1.
- 8. Remove the administrative commands from the protocol all together.
- It does not make sense for the protocol to define how a server is
- reconnected or shutdown, since they are implementation and
- configuration issues. Besides protocol provides only limited set of
- administrative commands and cannot define all that one could imagine.
- To be included in protocol version 1.1.
-
- 9. Add SILC_MESAGE_FLAG_REPLY for being other side to the
- SILC_MESSAGE_FLAG_REQUEST. Add generic SILC_MESSAGE_FLAG_DATA, which
- can include generic payload, which can include generic data. The
- payload definition is left out for now. To be included in protocol
- version 1.1.
-
- 10. Check command reply error status types in various commands,
- specifically NO_FOPRIV is missing from many commands. To be
- included in protocol version 1.1.
-
11. Change the wording in Private Message Key Payload definition to
describe the problems of trusting the payload, and to indicate that
the receiver may not accept the key in the payload, and to describe
other means of distributing a key.
- 13. Add the killer's client ID to the KILLED notify. To be included in
- protocol version 1.1.
-
- 14. The length of Arguments Num field in Notify Payload and Command
- Payload enforces that total of 256 arguments can be associated
- to a such payload. However, command-xx draft specified much higher
- values, and these should be fixed.
-
- 15. The LEAVE command reply should return the Channel ID of the channel
- that was parted.
-
16. Add STATS command after all to the protocol for providing practically
same information client gets when connects to a server. Normal
server would send this to router always when received from client.
-
i Set/unset channel as invite only channel
t Set/unset that only channel operator or
founder may set channel topic
+ m Set/unset user silencing. Normal users
+ are not able to talk on channel. Only
+ channel founder may set this mode
+ M Set/unset operator silencing. Operators
+ are not able to talk on channel. Only
+ channel founder may set this mode
l <limit> Set/unset channel's user limit
a <passphrase> Set/unset passphrase for channel that must
be provided when joining to the channel.
{ "ban_list", "channel {channel $0} ban list: $1", 2, { 0, 0 } },
{ "no_ban_list", "channel {channel $0} ban list not set", 1, { 0 } },
{ "inviting", "Inviting {nick $0} to channel {channel $1}", 2, { 0, 0 } },
- { "kicked_you", "You have been kicked off channel {channel $0} by {nick $1} ($2)", 3, { 0, 0 } },
- { "kicked", "{nick $0} has been kicked off channel {channel $1} by {nick $2} ($3)", 4, { 0, 0, 0 } },
- { "killed_you", "You have been killed from the SILC Network", 0 },
- { "killed", "{nick $0} has been killed from the SILC Network ($1)", 2, { 0, 0 } },
+ { "kicked_you", "You have been kicked off channel {channel $0} by {nick $1} ($2)", 3, { 0, 0, 0 } },
+ { "kicked", "{nick $0} has been kicked off channel {channel $1} by {nick $2} ($3)", 4, { 0, 0, 0, 0 } },
+ { "killed_you", "You have been killed from the SILC Network by {nick $0} ($1)", 2, { 0, 0 } },
+ { "killed", "{nick $0} has been killed from the SILC Network by {nick $1} ($2)", 3, { 0, 0, 0 } },
/* WHOIS, WHOWAS and USERS (alias WHO) messages */
{ NULL, "Who Queries", 0 },
void silc_channel_message(SilcClient client, SilcClientConnection conn,
SilcClientEntry sender, SilcChannelEntry channel,
- SilcMessageFlags flags, char *msg)
+ SilcMessageFlags flags, const unsigned char *message,
+ SilcUInt32 message_len)
{
SILC_SERVER_REC *server;
SILC_NICK_REC *nick;
SILC_LOG_DEBUG(("Start"));
- if (!msg)
+ if (!message)
return;
server = conn == NULL ? NULL : conn->context;
if (flags & SILC_MESSAGE_FLAG_ACTION)
printformat_module("fe-common/silc", server, channel->channel_name,
MSGLEVEL_ACTIONS, SILCTXT_CHANNEL_ACTION,
- nick == NULL ? "[<unknown>]" : nick->nick, msg);
+ nick == NULL ? "[<unknown>]" : nick->nick, message);
else if (flags & SILC_MESSAGE_FLAG_NOTICE)
printformat_module("fe-common/silc", server, channel->channel_name,
MSGLEVEL_NOTICES, SILCTXT_CHANNEL_NOTICE,
- nick == NULL ? "[<unknown>]" : nick->nick, msg);
+ nick == NULL ? "[<unknown>]" : nick->nick, message);
else
- signal_emit("message public", 6, server, msg,
+ signal_emit("message public", 6, server, message,
nick == NULL ? "[<unknown>]" : nick->nick,
nick == NULL ? "" : nick->host == NULL ? "" : nick->host,
chanrec->name, nick);
void silc_private_message(SilcClient client, SilcClientConnection conn,
SilcClientEntry sender, SilcMessageFlags flags,
- char *msg)
+ const unsigned char *message,
+ SilcUInt32 message_len)
{
SILC_SERVER_REC *server;
char userhost[256];
if (sender->username)
snprintf(userhost, sizeof(userhost) - 1, "%s@%s",
sender->username, sender->hostname);
- signal_emit("message private", 4, server, msg,
+ signal_emit("message private", 4, server, message,
sender->nickname ? sender->nickname : "[<unknown>]",
sender->username ? userhost : NULL);
}
client_entry = va_arg(va, SilcClientEntry);
tmp = va_arg(va, char *);
+ client_entry2 = va_arg(va, SilcClientEntry);
if (client_entry == conn->local_entry) {
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED_YOU,
+ client_entry2 ? client_entry2->nickname : "",
tmp ? tmp : "");
} else {
list1 = nicklist_get_same_unique(SERVER(server), client_entry);
printformat_module("fe-common/silc", server, NULL,
MSGLEVEL_CRAP, SILCTXT_CHANNEL_KILLED,
client_entry->nickname,
+ client_entry2 ? client_entry2->nickname : "",
tmp ? tmp : "");
}
break;
void silc_channel_message(SilcClient client, SilcClientConnection conn,
SilcClientEntry sender,
SilcChannelEntry channel,
- SilcMessageFlags flags, char *msg);
+ SilcMessageFlags flags,
+ const unsigned char *message,
+ SilcUInt32 message_len);
void silc_private_message(SilcClient client, SilcClientConnection conn,
SilcClientEntry sender,
- SilcMessageFlags flags, char *msg);
+ SilcMessageFlags flags,
+ const unsigned char *message,
+ SilcUInt32 message_len);
void silc_notify(SilcClient client, SilcClientConnection conn,
SilcNotifyType type, ...);
void silc_command(SilcClient client, SilcClientConnection conn,
SILC_SERVER_CMD(quit, QUIT, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(kill, KILL, SILC_CF_LAG_STRICT | SILC_CF_REG | SILC_CF_OPER),
SILC_SERVER_CMD(info, INFO, SILC_CF_LAG | SILC_CF_REG),
- SILC_SERVER_CMD(connect, CONNECT,
- SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
SILC_SERVER_CMD(ping, PING, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(oper, OPER, SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
SILC_SERVER_CMD(join, JOIN, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(ban, BAN, SILC_CF_LAG_STRICT | SILC_CF_REG),
- SILC_SERVER_CMD(close, CLOSE,
- SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
- SILC_SERVER_CMD(shutdown, SHUTDOWN, SILC_CF_LAG | SILC_CF_REG |
- SILC_CF_OPER),
SILC_SERVER_CMD(silcoper, SILCOPER,
SILC_CF_LAG | SILC_CF_REG | SILC_CF_SILC_OPER),
SILC_SERVER_CMD(leave, LEAVE, SILC_CF_LAG_STRICT | SILC_CF_REG),
SILC_SERVER_CMD(users, USERS, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(getkey, GETKEY, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(connect, PRIV_CONNECT,
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(close, PRIV_CLOSE,
+ SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
+ SILC_SERVER_CMD(shutdown, PRIV_SHUTDOWN, SILC_CF_LAG | SILC_CF_REG |
+ SILC_CF_OPER),
+
{ NULL, 0 },
};
if (cmd->cmd == command)
break;
- if (cmd == NULL) {
+ if (!cmd || !cmd->cb) {
silc_server_command_send_status_reply(ctx, command,
SILC_STATUS_ERR_UNKNOWN_COMMAND);
silc_server_command_free(ctx);
silc_server_send_notify_nick_change(server, server->router->connection,
server->server_type == SILC_SERVER ?
FALSE : TRUE, client->id,
- new_id);
+ new_id, nick);
oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Send NICK_CHANGE notify to the client's channels */
silc_server_send_notify_on_channels(server, NULL, client,
- SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
+ SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
oidp->data, oidp->len,
- nidp->data, nidp->len);
+ nidp->data, nidp->len,
+ client->nickname,
+ strlen(client->nickname));
send_reply:
/* Send the new Client ID as reply command back to client */
SilcClientID *client_id;
unsigned char *tmp, *comment;
SilcUInt32 tmp_len, tmp_len2;
+ SilcBuffer killer;
bool local;
SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_KILL, cmd, 1, 2);
/* Get comment */
comment = silc_argument_get_arg_type(cmd->args, 2, &tmp_len2);
if (tmp_len2 > 128)
- comment = NULL;
+ tmp_len2 = 128;
/* Send reply to the sender */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_KILL,
/* Send KILLED notify to the channels. It is not sent to the client
as it will be sent differently destined directly to the client and not
to the channel. */
+ killer = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
silc_server_send_notify_on_channels(server, remote_client,
remote_client, SILC_NOTIFY_TYPE_KILLED,
- comment ? 2 : 1,
- tmp, tmp_len,
- comment, comment ? tmp_len2 : 0);
+ 3, tmp, tmp_len,
+ comment, comment ? tmp_len2 : 0,
+ killer->data, killer->len);
+ silc_buffer_free(killer);
/* Send KILLED notify to primary route */
if (!server->standalone)
silc_server_send_notify_killed(server, server->router->connection, TRUE,
- remote_client->id, comment);
+ remote_client->id, comment, client->id);
/* Send KILLED notify to the client directly */
silc_server_send_notify_killed(server, remote_client->connection ?
remote_client->connection :
remote_client->router->connection, FALSE,
- remote_client->id, comment);
+ remote_client->id, comment, client->id);
/* Remove the client from all channels. This generates new keys to the
channels as well. */
/* Check that client has rights to change any requested channel modes */
if (!silc_server_check_cmode_rights(server, channel, chl, mode_mask)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
- SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ (chl->mode == 0 ?
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV :
+ SILC_STATUS_ERR_NO_CHANNEL_FOPRIV));
goto out;
}
but themselves. */
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && client != target_client) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
- SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ SILC_STATUS_ERR_NO_CHANNEL_FOPRIV);
goto out;
}
silc_server_command_free(cmd);
}
-/* Server side command of CONNECT. Connects us to the specified remote
- server or router. */
-
-SILC_SERVER_CMD_FUNC(connect)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- unsigned char *tmp, *host;
- SilcUInt32 tmp_len;
- SilcUInt32 port = SILC_PORT;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CONNECT, cmd, 1, 2);
-
- if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
- goto out;
-
- /* Check whether client has the permissions. */
- if (client->mode == SILC_UMODE_NONE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
- SILC_STATUS_ERR_NO_SERVER_PRIV);
- goto out;
- }
-
- if (server->server_type == SILC_ROUTER &&
- client->mode & SILC_UMODE_SERVER_OPERATOR) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
- SILC_STATUS_ERR_NO_ROUTER_PRIV);
- goto out;
- }
-
- /* Get the remote server */
- host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!host) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- /* Get port */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp)
- SILC_GET32_MSB(port, tmp);
-
- /* Create the connection. It is done with timeout and is async. */
- silc_server_create_connection(server, host, port);
-
- /* Send reply to the sender */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CONNECT,
- SILC_STATUS_OK);
-
- out:
- silc_server_command_free(cmd);
-}
-
/* Server side of command BAN. This is used to manage the ban list of the
channel. To add clients and remove clients from the ban list. */
silc_server_command_free(cmd);
}
-/* Server side command of CLOSE. Closes connection to a specified server. */
-
-SILC_SERVER_CMD_FUNC(close)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
- SilcServerEntry server_entry;
- SilcSocketConnection sock;
- unsigned char *tmp;
- SilcUInt32 tmp_len;
- unsigned char *name;
- SilcUInt32 port = SILC_PORT;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_CLOSE, cmd, 1, 2);
-
- if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
- goto out;
-
- /* Check whether client has the permissions. */
- if (client->mode == SILC_UMODE_NONE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
- SILC_STATUS_ERR_NO_SERVER_PRIV);
- goto out;
- }
-
- /* Get the remote server */
- name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- if (!name) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
- }
-
- /* Get port */
- tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (tmp)
- SILC_GET32_MSB(port, tmp);
-
- server_entry = silc_idlist_find_server_by_conn(server->local_list,
- name, port, FALSE, NULL);
- if (!server_entry)
- server_entry = silc_idlist_find_server_by_conn(server->global_list,
- name, port, FALSE, NULL);
- if (!server_entry) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
- SILC_STATUS_ERR_NO_SERVER_ID);
- goto out;
- }
-
- /* Send reply to the sender */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_CLOSE,
- SILC_STATUS_OK);
-
- /* Close the connection to the server */
- sock = (SilcSocketConnection)server_entry->connection;
-
- /* If we shutdown primary router connection manually then don't trigger
- any reconnect or backup router connections, by setting the router
- to NULL here. */
- if (server->router == server_entry) {
- server->id_entry->router = NULL;
- server->router = NULL;
- server->standalone = TRUE;
- }
- silc_server_free_sock_user_data(server, sock, NULL);
- silc_server_close_connection(server, sock);
-
- out:
- silc_server_command_free(cmd);
-}
-
-/* Server side command of SHUTDOWN. Shutdowns the server and closes all
- active connections. */
-
-SILC_SERVER_CMD_FUNC(shutdown)
-{
- SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcServer server = cmd->server;
- SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
-
- SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_SHUTDOWN, cmd, 0, 0);
-
- if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
- goto out;
-
- /* Check whether client has the permission. */
- if (client->mode == SILC_UMODE_NONE) {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
- SILC_STATUS_ERR_NO_SERVER_PRIV);
- goto out;
- }
-
- /* Send reply to the sender */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_SHUTDOWN,
- SILC_STATUS_OK);
-
- /* Then, gracefully, or not, bring the server down. */
- silc_server_stop(server);
- exit(0);
-
- out:
- silc_server_command_free(cmd);
-}
-
/* Server side command of LEAVE. Removes client from a channel. */
SILC_SERVER_CMD_FUNC(leave)
server->server_type == SILC_ROUTER ?
TRUE : FALSE, channel, id_entry->id);
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
- SILC_STATUS_OK);
+ silc_server_command_send_status_data(cmd, SILC_COMMAND_LEAVE,
+ SILC_STATUS_OK, 2, tmp, len);
/* Remove client from channel */
if (!silc_server_remove_from_one_channel(server, sock, channel, id_entry,
silc_free(server_id);
silc_server_command_free(cmd);
}
+
+
+/* Private range commands, specific to this implementation */
+
+/* Server side command of CONNECT. Connects us to the specified remote
+ server or router. */
+
+SILC_SERVER_CMD_FUNC(connect)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ unsigned char *tmp, *host;
+ SilcUInt32 tmp_len;
+ SilcUInt32 port = SILC_PORT;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CONNECT, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Check whether client has the permissions. */
+ if (client->mode == SILC_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
+ SILC_STATUS_ERR_NO_SERVER_PRIV);
+ goto out;
+ }
+
+ if (server->server_type == SILC_ROUTER &&
+ client->mode & SILC_UMODE_SERVER_OPERATOR) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
+ SILC_STATUS_ERR_NO_ROUTER_PRIV);
+ goto out;
+ }
+
+ /* Get the remote server */
+ host = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!host) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get port */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp)
+ SILC_GET32_MSB(port, tmp);
+
+ /* Create the connection. It is done with timeout and is async. */
+ silc_server_create_connection(server, host, port);
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CONNECT,
+ SILC_STATUS_OK);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side command of CLOSE. Closes connection to a specified server. */
+
+SILC_SERVER_CMD_FUNC(close)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcServerEntry server_entry;
+ SilcSocketConnection sock;
+ unsigned char *tmp;
+ SilcUInt32 tmp_len;
+ unsigned char *name;
+ SilcUInt32 port = SILC_PORT;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_CLOSE, cmd, 1, 2);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Check whether client has the permissions. */
+ if (client->mode == SILC_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+ SILC_STATUS_ERR_NO_SERVER_PRIV);
+ goto out;
+ }
+
+ /* Get the remote server */
+ name = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!name) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Get port */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (tmp)
+ SILC_GET32_MSB(port, tmp);
+
+ server_entry = silc_idlist_find_server_by_conn(server->local_list,
+ name, port, FALSE, NULL);
+ if (!server_entry)
+ server_entry = silc_idlist_find_server_by_conn(server->global_list,
+ name, port, FALSE, NULL);
+ if (!server_entry) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+ SILC_STATUS_ERR_NO_SERVER_ID);
+ goto out;
+ }
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_CLOSE,
+ SILC_STATUS_OK);
+
+ /* Close the connection to the server */
+ sock = (SilcSocketConnection)server_entry->connection;
+
+ /* If we shutdown primary router connection manually then don't trigger
+ any reconnect or backup router connections, by setting the router
+ to NULL here. */
+ if (server->router == server_entry) {
+ server->id_entry->router = NULL;
+ server->router = NULL;
+ server->standalone = TRUE;
+ }
+ silc_server_free_sock_user_data(server, sock, NULL);
+ silc_server_close_connection(server, sock);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side command of SHUTDOWN. Shutdowns the server and closes all
+ active connections. */
+
+SILC_SERVER_CMD_FUNC(shutdown)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+
+ SILC_SERVER_COMMAND_CHECK(SILC_COMMAND_PRIV_SHUTDOWN, cmd, 0, 0);
+
+ if (!client || cmd->sock->type != SILC_SOCKET_TYPE_CLIENT)
+ goto out;
+
+ /* Check whether client has the permission. */
+ if (client->mode == SILC_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_SHUTDOWN,
+ SILC_STATUS_ERR_NO_SERVER_PRIV);
+ goto out;
+ }
+
+ /* Send reply to the sender */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_PRIV_SHUTDOWN,
+ SILC_STATUS_OK);
+
+ /* Then, gracefully, or not, bring the server down. */
+ silc_server_stop(server);
+ exit(0);
+
+ out:
+ silc_server_command_free(cmd);
+}
SILC_SERVER_CMD_FUNC(quit);
SILC_SERVER_CMD_FUNC(kill);
SILC_SERVER_CMD_FUNC(info);
-SILC_SERVER_CMD_FUNC(connect);
SILC_SERVER_CMD_FUNC(ping);
SILC_SERVER_CMD_FUNC(oper);
-SILC_SERVER_CMD_FUNC(pass);
-SILC_SERVER_CMD_FUNC(admin);
SILC_SERVER_CMD_FUNC(join);
SILC_SERVER_CMD_FUNC(motd);
SILC_SERVER_CMD_FUNC(umode);
SILC_SERVER_CMD_FUNC(cmode);
SILC_SERVER_CMD_FUNC(cumode);
SILC_SERVER_CMD_FUNC(kick);
-SILC_SERVER_CMD_FUNC(ignore);
SILC_SERVER_CMD_FUNC(ban);
-SILC_SERVER_CMD_FUNC(close);
-SILC_SERVER_CMD_FUNC(shutdown);
SILC_SERVER_CMD_FUNC(silcoper);
SILC_SERVER_CMD_FUNC(leave);
SILC_SERVER_CMD_FUNC(users);
SILC_SERVER_CMD_FUNC(getkey);
+SILC_SERVER_CMD_FUNC(connect);
+SILC_SERVER_CMD_FUNC(close);
+SILC_SERVER_CMD_FUNC(shutdown);
+
#endif
SilcClientEntry
silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
- SilcClientID *new_id)
+ SilcClientID *new_id, const char *nickname)
{
SilcIDCacheEntry id_cache = NULL;
SilcClientEntry client;
/* Remove the old entry and add a new one */
- silc_idcache_del_by_context(id_list->clients, client);
+ if (!silc_idcache_del_by_context(id_list->clients, client))
+ return NULL;
silc_free(client->id);
+ silc_free(client->nickname);
client->id = new_id;
+ client->nickname = nickname ? strdup(nickname) : NULL;
- silc_idcache_add(id_list->clients, NULL, client->id, client, 0, NULL);
+ if (!silc_idcache_add(id_list->clients, client->nickname, client->id,
+ client, 0, NULL))
+ return NULL;
SILC_LOG_DEBUG(("Replaced"));
bool registered, SilcIDCacheEntry *ret_entry);
SilcClientEntry
silc_idlist_replace_client_id(SilcIDList id_list, SilcClientID *old_id,
- SilcClientID *new_id);
+ SilcClientID *new_id, const char *nickname);
void silc_idlist_client_destructor(SilcIDCache cache,
SilcIDCacheEntry entry);
SilcChannelEntry
* Distribute the notify to local clients on the channel
*/
unsigned char *id, *id2;
+ char *nickname;
+ SilcUInt32 nickname_len;
SILC_LOG_DEBUG(("NICK CHANGE notify"));
SILC_LOG_DEBUG(("New Client ID id(%s)",
silc_id_render(client_id2, SILC_ID_CLIENT)));
+ /* From protocol version 1.1 we also get the new nickname */
+ nickname = silc_argument_get_arg_type(args, 3, &nickname_len);;
+
/* Replace the Client ID */
client = silc_idlist_replace_client_id(server->global_list, client_id,
- client_id2);
+ client_id2, nickname);
if (!client)
client = silc_idlist_replace_client_id(server->local_list, client_id,
- client_id2);
+ client_id2, nickname);
if (client) {
- /* The nickname is not valid anymore, set it NULL. This causes that
- the nickname will be queried if someone wants to know it. */
- if (client->nickname)
- silc_free(client->nickname);
- client->nickname = NULL;
-
/* Send the NICK_CHANGE notify type to local clients on the channels
this client is joined to. */
- silc_server_send_notify_on_channels(server, NULL, client,
- SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
- id, tmp_len,
- id2, tmp_len);
+ silc_server_send_notify_on_channels(server, NULL, client,
+ SILC_NOTIFY_TYPE_NICK_CHANGE, 3,
+ id, tmp_len, id2, tmp_len,
+ nickname, nickname ?
+ nickname_len : 0);
}
silc_free(client_id);
if (chl->mode & SILC_CHANNEL_UMODE_CHANFO)
goto out;
- /* Get kicker. In protocol version 1.0 this is not mandatory argument
- so we check it only if it is provided. */
+ /* From protocol version 1.1 we get the kicker's ID as well. */
tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
if (tmp) {
client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
/*
* Distribute the notify to local clients on channels
*/
- unsigned char *id;
- SilcUInt32 id_len;
+ unsigned char *id, *comment;
+ SilcUInt32 id_len, comment_len;
SILC_LOG_DEBUG(("KILLED notify"));
}
/* Get comment */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- if (tmp_len > 128)
- tmp = NULL;
+ comment = silc_argument_get_arg_type(args, 2, &comment_len);
+ if (comment_len > 128)
+ comment_len = 127;
+
+ /* From protocol version 1.1 we get the killer's ID as well. */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp) {
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
+
+ /* If the the client is not in local list we check global list */
+ client2 = silc_idlist_find_client_by_id(server->global_list,
+ client_id, TRUE, NULL);
+ if (!client2) {
+ client2 = silc_idlist_find_client_by_id(server->local_list,
+ client_id, TRUE, NULL);
+ if (!client2) {
+ silc_free(client_id);
+ goto out;
+ }
+ }
+ silc_free(client_id);
+
+ /* Killer must be router operator */
+ if (!(client2->mode & SILC_UMODE_ROUTER_OPERATOR)) {
+ SILC_LOG_DEBUG(("Killing is not allowed"));
+ goto out;
+ }
+ }
/* Send the notify to local clients on the channels except to the
client who is killed. */
silc_server_send_notify_on_channels(server, client, client,
- SILC_NOTIFY_TYPE_KILLED,
- tmp ? 2 : 1,
- id, id_len,
+ SILC_NOTIFY_TYPE_KILLED, 3,
+ id, id_len, comment, comment_len,
tmp, tmp_len);
/* Remove the client from all channels */
SilcChannelID *id = NULL;
void *sender_id = NULL;
SilcClientEntry sender_entry = NULL;
+ SilcChannelClientEntry chl;
bool local = TRUE;
SILC_LOG_DEBUG(("Processing channel message"));
sender_id, TRUE, NULL);
}
if (!sender_entry || !silc_server_client_on_channel(sender_entry,
- channel, NULL)) {
+ channel, &chl)) {
SILC_LOG_DEBUG(("Client not on channel"));
goto out;
}
+ /* If channel is moderated check that client is allowed to send
+ messages. */
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chl->mode) {
+ SILC_LOG_DEBUG(("Channel is silenced from normal users"));
+ goto out;
+ }
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
+ chl->mode & SILC_CHANNEL_UMODE_CHANOP &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANFO)) {
+ SILC_LOG_DEBUG(("Channel is silenced from operators"));
+ goto out;
+ }
+
/* If the packet is coming from router, but the client entry is local
entry to us then some router is rerouting this to us and it is not
allowed. When the client is local to us it means that we've routed
SilcSocketConnection sock,
bool broadcast,
SilcClientID *old_id,
- SilcClientID *new_id)
+ SilcClientID *new_id,
+ const char *nickname)
{
SilcBuffer idp1, idp2;
silc_server_send_notify(server, sock, broadcast,
SILC_NOTIFY_TYPE_NICK_CHANGE,
- 2, idp1->data, idp1->len, idp2->data, idp2->len);
+ 3, idp1->data, idp1->len, idp2->data, idp2->len,
+ nickname, nickname ? strlen(nickname) : 0);
silc_buffer_free(idp1);
silc_buffer_free(idp2);
}
SilcSocketConnection sock,
bool broadcast,
SilcClientID *client_id,
- char *comment)
+ char *comment,
+ SilcClientID *killer)
{
- SilcBuffer idp;
+ SilcBuffer idp1;
+ SilcBuffer idp2;
- idp = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp1 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ idp2 = silc_id_payload_encode((void *)killer, SILC_ID_CLIENT);
silc_server_send_notify_dest(server, sock, broadcast, (void *)client_id,
SILC_ID_CLIENT, SILC_NOTIFY_TYPE_KILLED,
- comment ? 2 : 1, idp->data, idp->len,
- comment, comment ? strlen(comment) : 0);
- silc_buffer_free(idp);
+ 3, idp1->data, idp1->len,
+ comment, comment ? strlen(comment) : 0,
+ idp2->data, idp2->len);
+ silc_buffer_free(idp1);
+ silc_buffer_free(idp2);
}
/* Sends UMODE_CHANGE notify type. This tells that `client_id' client's
SilcSocketConnection sock,
bool broadcast,
SilcClientID *old_id,
- SilcClientID *new_id);
+ SilcClientID *new_id,
+ const char *nickname);
void silc_server_send_notify_join(SilcServer server,
SilcSocketConnection sock,
bool broadcast,
SilcSocketConnection sock,
bool broadcast,
SilcClientID *client_id,
- char *comment);
+ char *comment,
+ SilcClientID *killer);
void silc_server_send_notify_umode(SilcServer server,
SilcSocketConnection sock,
bool broadcast,
SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
SilcUInt32 len, void *context)
{
- SilcSKEStatus status = SILC_SKE_STATUS_OK;
- char *cp;
- int maj = 0, min = 0, build = 0, maj2 = 0, min2 = 0, build2 = 0;
+ SilcUInt32 l_protocol_version = 0, r_protocol_version = 0;
SILC_LOG_INFO(("%s (%s) is version %s", ske->sock->hostname,
ske->sock->ip, version));
- /* Check for initial version string. Allowed "SILC-x.x-". More
- specific protocol version is checked later in session. */
- if (!strstr(version, "SILC-"))
- status = SILC_SKE_STATUS_BAD_VERSION;
-
- /* Check software version */
-
- cp = version + 9;
- if (!cp)
- status = SILC_SKE_STATUS_BAD_VERSION;
-
- maj = atoi(cp);
- cp = strchr(cp, '.');
- if (cp) {
- min = atoi(cp + 1);
- cp++;
- }
- if (cp) {
- cp = strchr(cp, '.');
- if (cp)
- build = atoi(cp + 1);
+ if (!silc_parse_version_string(version, &r_protocol_version, NULL, NULL,
+ NULL, NULL)) {
+ SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version",
+ ske->sock->hostname, ske->sock->ip, version));
+ return SILC_SKE_STATUS_BAD_VERSION;
}
- cp = silc_version_string + 9;
- if (!cp)
- status = SILC_SKE_STATUS_BAD_VERSION;
-
- maj2 = atoi(cp);
- cp = strchr(cp, '.');
- if (cp) {
- min2 = atoi(cp + 1);
- cp++;
- }
- if (cp) {
- cp = strchr(cp, '.');
- if (cp)
- build2 = atoi(cp + 1);
+ if (!silc_parse_version_string(silc_version_string,
+ &l_protocol_version, NULL, NULL,
+ NULL, NULL)) {
+ SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version",
+ ske->sock->hostname, ske->sock->ip, version));
+ return SILC_SKE_STATUS_BAD_VERSION;
}
- if (maj != maj2)
- status = SILC_SKE_STATUS_BAD_VERSION;
-
- if (status == SILC_SKE_STATUS_BAD_VERSION)
+ /* If remote is too new, don't connect */
+ if (l_protocol_version < r_protocol_version) {
SILC_LOG_ERROR(("%s (%s) %s is not allowed/supported version",
ske->sock->hostname, ske->sock->ip, version));
+ return SILC_SKE_STATUS_BAD_VERSION;
+ }
+
+ ske->sock->version = r_protocol_version;
- return status;
+ return SILC_SKE_STATUS_OK;
}
/* Callback that is called by the SKE to indicate that it is safe to
}
}
+ if (mode & SILC_CHANNEL_MODE_SILENCE_USERS) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS))
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS))
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
return TRUE;
}
1 SILC_COMMAND_WHOIS
- Max Arguments: 3328
+ Max Arguments: 256
Arguments: (1) [<nickname>[@<server>]] (2) [<count>]
(3) [<Client ID>] (n) [...]
3 SILC_COMMAND_IDENTIFY
- Max Arguments: 3328
+ Max Arguments: 256
Arguments: (1) [<nickname>[@<server>]] (2) [<server name>]
(3) [<channel name>] (4) [<count>]
(5) [<ID Payload>] (n) [...]
SILC_STATUS_ERR_NO_SERVER_ID
- 11 SILC_COMMAND_CONNECT
-
- Max Arguments: 2
- Arguments: (1) <remote server/router> (2) [<port>]
-
- This command is used by operators to force a server to try to
- establish a new connection to remote server or router. The
- Operator MUST specify the server/router to be connected by
- setting <remote server> argument. The port is 32 bit MSB value.
-
- Reply messages to the command:
-
- Max Arguments: 1
- Arguments: (1) <Status Payload>
-
- This command replies only with Status Payload.
-
-
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_WILDCARDS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NO_SERVER_PRIV
- SILC_STATUS_ERR_NO_ROUTER_PRIV
+ 11 <deprecated command>
12 SILC_COMMAND_PING
The following client modes are defined:
- 0x0000 SILC_UMODE_NONE
+ 0x00000000 SILC_UMODE_NONE
No specific mode for client. This is the initial
setting when new client is created. The client is
normal client now.
- 0x0001 SILC_UMODE_SERVER_OPERATOR
+ 0x00000001 SILC_UMODE_SERVER_OPERATOR
Marks the user as server operator. Client MUST NOT
set this mode itself. Server sets this mode to the
MAY unset the mode itself.
- 0x0002 SILC_UMODE_ROUTER_OPERATOR
+ 0x00000002 SILC_UMODE_ROUTER_OPERATOR
Marks the user as router (SILC) operator. Client
MUST NOT this mode itself. Router sets this mode to
MAY unset the mode itself.
- 0x0004 SILC_UMODE_GONE
+ 0x00000004 SILC_UMODE_GONE
Marks that the user is not currently present in the
SILC Network. Client MAY set and unset this mode.
The following channel modes are defined:
- 0x0000 SILC_CMODE_NONE
+ 0x00000000 SILC_CMODE_NONE
No specific mode on channel. This is the default when
channel is created. This means that channel is just plain
normal channel.
- 0x0001 SILC_CMODE_PRIVATE
+ 0x00000001 SILC_CMODE_PRIVATE
Channel is private channel. Private channels are shown
in the channel list listed with SILC_COMMAND_LIST command
to set/unset this mode.
- 0x0002 SILC_CMODE_SECRET
+ 0x00000002 SILC_CMODE_SECRET
Channel is secret channel. Secret channels are not shown
in the list listed with SILC_COMMAND_LIST command. Secret
to set/unset this mode.
- 0x0004 SILC_CMODE_PRIVKEY
+ 0x00000004 SILC_CMODE_PRIVKEY
Channel uses private channel key to protect the traffic
on the channel. When this mode is set the client will be
to set/unset this mode.
- 0x0008 SILC_CMODE_INVITE
+ 0x00000008 SILC_CMODE_INVITE
Channel is invite only channel. Client may join to this
channel only if it is invited to the channel. Channel
to set/unset this mode.
- 0x0010 SILC_CMODE_TOPIC
+ 0x00000010 SILC_CMODE_TOPIC
The topic of the channel may only be set by client that
is channel founder or channel operator. Normal clients
to set/unset this mode.
- 0x0020 SILC_CMODE_ULIMIT
+ 0x00000020 SILC_CMODE_ULIMIT
User limit has been set to the channel. New clients
may not join to the channel when the limit set is
to set/unset this mode.
- 0x0040 SILC_CMODE_PASSPHRASE
+ 0x00000040 SILC_CMODE_PASSPHRASE
Passphrase has been set to the channel. Client may
join to the channel only if it is able to provide the
to set/unset this mode.
- 0x0080 SILC_CMODE_CIPHER
+ 0x00000080 SILC_CMODE_CIPHER
Sets specific cipher to be used to protect channel
traffic. The <cipher> argument is the requested cipher.
to set/unset this mode.
- 0x0100 SILC_CMODE_HMAC
+ 0x00000100 SILC_CMODE_HMAC
Sets specific hmac to be used to compute the MACs of the
channel message. The <hmac> argument is the requested hmac.
to set/unset this mode.
- 0x0200 SILC_CMODE_FOUNDER_AUTH
+ 0x00000200 SILC_CMODE_FOUNDER_AUTH
Channel founder may set this mode to be able to regain
channel founder rights even if the client leaves the
Typical implementation would use [+|-]f on user interface
to set/unset this mode.
+
+ 0x00000400 SILC_CMODE_SILENCE_USERS
+
+ Channel founder may set this mode to silence normal users
+ on the channel. Users with operator privileges are not
+ affected by this mode. Messages sent by normal users
+ are dropped by servers when this mode is set. This mode
+ can be used to moderate the channel. Only channel founder
+ may set/unset this mode.
+
+
+ 0x00000800 SILC_CMODE_SILENCE_OPERS
+
+ Channel founder may set this mode to silence operators
+ on the channel. When used with SILC_CMODE_SILENCE_USERS
+ mode this can be used to set the channel in state where only
+ the founder of the channel may send messages to the channel.
+ Messages sent by operators are dropped by servers when this
+ mode is set. Only channel founder may set/unset this mode.
+
+
To make the mode system work, client MUST keep the channel mode
mask locally so that the mode setting and unsetting would work
without problems. The client receives the initial channel mode
SILC_STATUS_ERR_BAD_CHANNEL_ID
SILC_STATUS_ERR_NO_CHANNEL_ID
SILC_STATUS_ERR_NO_CHANNEL_PRIV
+ SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
SILC_STATUS_ERR_UNKNOWN_MODE
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
SILC_STATUS_ERR_AUTH_FAILED
The following channel modes are defined:
- 0x0000 SILC_CUMODE_NONE
+ 0x00000000 SILC_CUMODE_NONE
No specific mode. This is the normal situation for client.
Also, this is the mode set when removing all modes from
the target client.
- 0x0001 SILC_CUMODE_FOUNDER
+ 0x00000001 SILC_CUMODE_FOUNDER
The client is channel founder of the channel. Usually this
mode is set only by the server when the channel was created.
mode was set. The client MAY remove this mode at any time.
- 0x0002 SILC_CUMODE_OPERATOR
+ 0x00000002 SILC_CUMODE_OPERATOR
Sets channel operator privileges on the channel for a
client on the channel. Channel founder and channel operator
SILC_STATUS_ERR_BAD_CHANNEL_ID
SILC_STATUS_ERR_NO_CHANNEL_ID
SILC_STATUS_ERR_NO_CHANNEL_PRIV
+ SILC_STATUS_ERR_NO_CHANNEL_FOPRIV
SILC_STATUS_ERR_UNKNOWN_MODE
SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
SILC_STATUS_ERR_AUTH_FAILED
SILC_STATUS_ERR_NO_CHANNEL_PRIV
- 21 SILC_COMMAND_CLOSE
-
- Max Arguments: 2
- Arguments: (1) <remote server/router> (2) [<port>]
-
- This command is used only by operator to close connection to a
- remote site.
-
- Reply messages to the command:
-
- Max Arguments: 1
- Arguments: (1) <Status Payload>
+ 21 <deprecated command>
- This command replies only with Status Payload.
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
- SILC_STATUS_ERR_TOO_MANY_PARAMS
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NO_SUCH_SERVER
- SILC_STATUS_ERR_NO_SERVER_PRIV
- SILC_STATUS_ERR_NO_SUCH_SERVER_ID
-
-
- 22 SILC_COMMAND_SHUTDOWN
-
- Max Arguments: 0
- Arguments: None
-
- This command is used only by operator to shutdown the server.
- All connections to the server will be closed and the server is
- shutdown.
-
- Reply messages to the command:
-
- Max Arguments: 1
- Arguments: (1) <Status Payload>
-
- This command replies only with Status Payload.
-
- Status messages:
-
- SILC_STATUS_OK
- SILC_STATUS_ERR_NOT_REGISTERED
- SILC_STATUS_ERR_NO_SERVER_PRIV
+ 22 <deprecated command>
23 SILC_COMMAND_SILCOPER
Reply messages to the command:
- Max Arguments: 1
- Arguments: (1) <Status Payload>
+ Max Arguments: 2
+ Arguments: (1) <Status Payload> (2) <Channel ID>
- This command replies only with Status Payload.
+ The <Channel ID> is the ID of left channel.
Status messages:
receiving the packet distributes this type to the local clients
on the channel and broadcast it to the network.
- Max Arguments: 2
+ Max Arguments: 3
Arguments: (1) <Old Client ID> (2) <New Client ID>
+ (3) <nickname>
The <Old Client ID> is the old ID of the client which changed
the nickname. The <New Client ID> is the new ID generated by
- the change of the nickname.
+ the change of the nickname. The <nickname> is the new nickname.
7 SILC_NOTIFY_TYPE_CMODE_CHANGE
or server receiving the packet distributes this type to the local
clients on the channel and broadcast it to the network.
- Max Arguments: 2
- Arguments: (1) <Client ID> (2) [<comment>]
+ Max Arguments: 3
+ Arguments: (1) <Client ID> (2) [<comment>]
+ (3) <Killer's Client ID>
The <Client ID> is the client which was killed from the network.
The killer may have set the <comment> to indicate the reason for
- the killing.
+ the killing. The <Killer's Client ID> is the killer.
14 SILC_NOTIFY_TYPE_UMODE_CHANGE
of the signing process and any associated payloads
of this flag.
- 0x0040 - 0x0200 RESERVED
+ 0x0040 SILC_MESSAGE_FLAG_REPLY
+
+ This is a generic reply flag to send a reply to
+ previously received request. A separate document
+ should define any payloads associated to this flag.
+
+ 0x0080 SILC_MESSAGE_FLAG_DATA
+
+ This is a generic data flag, indicating that the
+ message includes some data which can be interpreted
+ in a specific way. Using this flag any kind of data
+ can be delivered inside message payload. A separate
+ document should define how this flag is interpreted
+ and define any associated payloads.
+
+ 0x0100 - 0x0800 RESERVED
Reserved for future flags
- 0x0400 - 0x8000 PRIVATE RANGE
+ 0x1000 - 0x8000 PRIVATE RANGE
Private range for free use.
Protocol version MAY provide both major and minor version. Currently
implementations MUST set the protocol version and accept the protocol
-version as SILC-1.0-<software version>. If new protocol version causes
+version as SILC-1.1-<software version>. If new protocol version causes
in compatibilities with older version the the <minor> versio number MUST
be incremented. The <major> is incremented if new protocol version is
fully incompatible.
Thus, the version strings could be, for example:
.in 6
-SILC-1.0-1.2
SILC-1.1-2.0.2
-SILC-1.0-1.0.VendorXYZ
+SILC-1.0-1.2
+SILC-1.1-1.0.VendorXYZ
.in 3
# number of the software. The string can be a regex string to match
# more widely. Usually the vendor version checking is not necessary
# and can be omitted. These can be overridden with ConnectionParams.
- #version_protocol = "1.0";
+ #version_protocol = "1.1";
#version_software = "1.3";
#version_software_vendor = "SomeVendor";
# number of the software. The string can be a regex string to match
# more widely. Usually the vendor version checking is not necessary
# and can be omitted.
- #version_protocol = "1.0";
+ #version_protocol = "1.1";
#version_software = "1.3";
#version_software_vendor = "SomeVendor";
unsigned char *id_string;
SilcUInt32 iv_len;
int block_len;
+ SilcChannelUser chu;
SILC_LOG_DEBUG(("Sending packet to channel"));
+ chu = silc_client_on_channel(channel, conn->local_entry);
+ if (!chu) {
+ SILC_LOG_ERROR(("Cannot send message to channel we are not joined"));
+ return;
+ }
+
+ /* Check if it is allowed to send messages to this channel by us. */
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_USERS && !chu->mode)
+ return;
+ if (channel->mode & SILC_CHANNEL_MODE_SILENCE_OPERS &&
+ chu->mode & SILC_CHANNEL_UMODE_CHANOP &&
+ !(chu->mode & SILC_CHANNEL_UMODE_CHANFO))
+ return;
+
/* Take the key to be used */
if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
if (key) {
if (clients_count == 1) {
SilcChannelEntry channel;
unsigned char *message;
+ SilcUInt32 message_len;
channel = silc_client_get_channel_by_id(client, conn, res->channel_id);
if (!channel)
silc_hash_table_add(clients[0]->channels, channel, chu);
}
- message = silc_channel_message_get_data(res->payload, NULL);
+ message = silc_channel_message_get_data(res->payload, &message_len);
/* Pass the message to application */
client->internal->ops->channel_message(
client, conn, clients[0], channel,
silc_channel_message_get_flags(res->payload),
- message);
+ message, message_len);
}
out:
SilcClientEntry client_entry;
SilcClientID *client_id = NULL;
unsigned char *message;
+ SilcUInt32 message_len;
SILC_LOG_DEBUG(("Start"));
goto out;
}
- message = silc_channel_message_get_data(payload, NULL);
+ message = silc_channel_message_get_data(payload, &message_len);
/* Pass the message to application */
client->internal->ops->channel_message(
client, conn, client_entry, channel,
silc_channel_message_get_flags(payload),
- message);
+ message, message_len);
out:
silc_free(id);
if (!client_id)
goto out;
- /* Find Client entry and if not found resolve it */
- client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
- if (!client_entry2) {
- /* Resolve the entry information */
- silc_client_notify_by_server_resolve(client, conn, packet,
- SILC_ID_CLIENT, client_id);
-
- /* Add the new entry even though we resolved it. This is because we
- want to replace the old entry with the new entry here right now. */
- client_entry2 =
- silc_client_add_client(client, conn, NULL, NULL, NULL,
- silc_id_dup(client_id, SILC_ID_CLIENT),
- client_entry->mode);
+ /* From protocol version 1.1 we get the new nickname in notify as well,
+ so we don't have to resolve it. Do it the hard way if server doesn't
+ send it to us. */
+ tmp = silc_argument_get_arg_type(args, 3, NULL);
+ if (tmp) {
+ /* Protocol version 1.1 */
+
+ /* Create new client entry, and save all old information with the
+ new nickname and client ID */
+ client_entry2 = silc_client_add_client(client, conn, NULL, NULL,
+ client_entry->realname,
+ silc_id_dup(client_id,
+ SILC_ID_CLIENT), 0);
+ if (!client_entry2)
+ goto out;
- /* Replace old ID entry with new one on all channels. */
- silc_client_replace_from_channels(client, conn, client_entry,
- client_entry2);
+ if (client_entry->server)
+ client_entry2->server = strdup(client_entry->server);
+ if (client_entry->username)
+ client_entry2->username = strdup(client_entry->username);
+ if (client_entry->hostname)
+ client_entry2->hostname = strdup(client_entry->hostname);
+ silc_client_update_client(client, conn, client_entry2, tmp, NULL, NULL,
+ client_entry->mode);
} else {
+ /* Protocol version 1.0 */
+
+ /* Find client entry and if not found resolve it */
+ client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry2) {
+ /* Resolve the entry information */
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+
+ /* Add the new entry even though we resolved it. This is because we
+ want to replace the old entry with the new entry here right now. */
+ client_entry2 =
+ silc_client_add_client(client, conn, NULL, NULL, NULL,
+ silc_id_dup(client_id, SILC_ID_CLIENT),
+ client_entry->mode);
+
+ /* Replace old ID entry with new one on all channels. */
+ silc_client_replace_from_channels(client, conn, client_entry,
+ client_entry2);
+ break;
+ }
+
if (client_entry2 != conn->local_entry)
silc_client_nickname_format(client, conn, client_entry2);
+ }
- /* Remove the old from cache */
- silc_idcache_del_by_context(conn->client_cache, client_entry);
-
- /* Replace old ID entry with new one on all channels. */
- silc_client_replace_from_channels(client, conn, client_entry,
- client_entry2);
+ /* Remove the old from cache */
+ silc_idcache_del_by_context(conn->client_cache, client_entry);
+
+ /* Replace old ID entry with new one on all channels. */
+ silc_client_replace_from_channels(client, conn, client_entry,
+ client_entry2);
- /* Notify application */
- client->internal->ops->notify(client, conn, type,
- client_entry, client_entry2);
+ /* Notify application */
+ client->internal->ops->notify(client, conn, type,
+ client_entry, client_entry2);
+
+ /* Free old client entry */
+ silc_client_del_client_entry(client, conn, client_entry);
- /* Free data */
- silc_client_del_client_entry(client, conn, client_entry);
- }
break;
case SILC_NOTIFY_TYPE_CMODE_CHANGE:
if (!channel)
break;
- /* Get the kicker */
+ /* From protocol version 1.1 we get the kicker's client ID as well */
tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
if (tmp) {
+ silc_free(client_id);
client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
if (!client_id)
goto out;
break;
case SILC_NOTIFY_TYPE_KILLED:
- /*
- * A client (maybe me) was killed from the network.
- */
+ {
+ /*
+ * A client (maybe me) was killed from the network.
+ */
+ char *comment;
+ SilcUInt32 comment_len;
- SILC_LOG_DEBUG(("Notify: KILLED"));
+ SILC_LOG_DEBUG(("Notify: KILLED"));
- /* Get Client ID */
- tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- if (!tmp)
- goto out;
-
- client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
- if (!client_id)
- goto out;
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Find Client entry */
- client_entry = silc_client_get_client_by_id(client, conn, client_id);
- if (!client_entry)
- goto out;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
- /* Get comment */
- tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ /* Find Client entry */
+ client_entry = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry)
+ goto out;
- /* Notify application. */
- client->internal->ops->notify(client, conn, type, client_entry, tmp);
+ /* Get comment */
+ comment = silc_argument_get_arg_type(args, 2, &comment_len);
+
+ /* From protocol version 1.1 we get killer's client ID as well */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp) {
+ silc_free(client_id);
+ client_id = silc_id_payload_parse_id(tmp, tmp_len, NULL);
+ if (!client_id)
+ goto out;
+
+ /* Find killer's client entry and if not found resolve it */
+ client_entry2 = silc_client_get_client_by_id(client, conn, client_id);
+ if (!client_entry2) {
+ silc_client_notify_by_server_resolve(client, conn, packet,
+ SILC_ID_CLIENT, client_id);
+ goto out;
+ } else {
+ if (client_entry2 != conn->local_entry)
+ silc_client_nickname_format(client, conn, client_entry2);
+ }
+ }
- if (client_entry != conn->local_entry)
- /* Remove the client from all channels and free it */
- silc_client_del_client(client, conn, client_entry);
+ /* Notify application. */
+ client->internal->ops->notify(client, conn, type, client_entry,
+ comment, client_entry2);
+ if (client_entry != conn->local_entry)
+ /* Remove the client from all channels and free it */
+ silc_client_del_client(client, conn, client_entry);
+ }
break;
case SILC_NOTIFY_TYPE_SERVER_SIGNOFF:
static void
silc_channel_message(SilcClient client, SilcClientConnection conn,
SilcClientEntry sender, SilcChannelEntry channel,
- SilcMessageFlags flags, char *msg)
+ SilcMessageFlags flags, const unsigned char *message,
+ SilcUInt32 message_len);
{
}
static void
silc_private_message(SilcClient client, SilcClientConnection conn,
- SilcClientEntry sender, SilcMessageFlags flags, char *msg)
+ SilcClientEntry sender, SilcMessageFlags flags,
+ const unsigned char *message,
+ SilcUInt32 message_len);
{
}
SilcClientID *remote_id = NULL;
SilcClientEntry remote_client;
SilcMessageFlags flags;
+ unsigned char *message;
+ SilcUInt32 message_len;
if (packet->src_id_type != SILC_ID_CLIENT)
goto out;
flags = silc_private_message_get_flags(payload);
/* Pass the private message to application */
- client->internal->ops->private_message(
- client, conn, remote_client, flags,
- silc_private_message_get_message(payload,
- NULL));
+ message = silc_private_message_get_message(payload, &message_len);
+ client->internal->ops->private_message(client, conn, remote_client, flags,
+ message, message_len);
/* See if we are away (gone). If we are away we will reply to the
sender with the set away message. */
else
mode &= ~SILC_CHANNEL_MODE_TOPIC;
break;
+ case 'm':
+ if (add)
+ mode |= SILC_CHANNEL_MODE_SILENCE_USERS;
+ else
+ mode &= ~SILC_CHANNEL_MODE_SILENCE_USERS;
+ break;
+ case 'M':
+ if (add)
+ mode |= SILC_CHANNEL_MODE_SILENCE_OPERS;
+ else
+ mode &= ~SILC_CHANNEL_MODE_SILENCE_OPERS;
+ break;
case 'l':
if (add) {
int ll;
silc_client_command_free(cmd);
}
-/* CONNECT command. Connects the server to another server. */
-
-SILC_CLIENT_CMD_FUNC(connect)
-{
- SilcClientCommandContext cmd = (SilcClientCommandContext)context;
- SilcClientConnection conn = cmd->conn;
- SilcBuffer buffer;
- unsigned char port[4];
- SilcUInt32 tmp;
-
- if (!cmd->conn) {
- SILC_NOT_CONNECTED(cmd->client, cmd->conn);
- COMMAND_ERROR;
- goto out;
- }
-
- if (cmd->argc < 2) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CONNECT <server> [<port>]");
- COMMAND_ERROR;
- goto out;
- }
-
- if (cmd->argc == 3) {
- tmp = atoi(cmd->argv[2]);
- SILC_PUT32_MSB(tmp, port);
- }
-
- if (cmd->argc == 3)
- buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 2,
- 1, cmd->argv[1],
- strlen(cmd->argv[1]),
- 2, port, 4);
- else
- buffer = silc_command_payload_encode_va(SILC_COMMAND_CONNECT, 0, 1,
- 1, cmd->argv[1],
- strlen(cmd->argv[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);
-
- /* Notify application */
- COMMAND;
-
- out:
- silc_client_command_free(cmd);
-}
-
/* Command BAN. This is used to manage the ban list of the channel. */
SILC_CLIENT_CMD_FUNC(ban)
silc_client_command_free(cmd);
}
-/* CLOSE command. Close server connection to the remote server */
-
-SILC_CLIENT_CMD_FUNC(close)
-{
- SilcClientCommandContext cmd = (SilcClientCommandContext)context;
- SilcClientConnection conn = cmd->conn;
- SilcBuffer buffer;
- unsigned char port[4];
- SilcUInt32 tmp;
-
- if (!cmd->conn) {
- SILC_NOT_CONNECTED(cmd->client, cmd->conn);
- COMMAND_ERROR;
- goto out;
- }
-
- if (cmd->argc < 2) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
- "Usage: /CLOSE <server> [<port>]");
- COMMAND_ERROR;
- goto out;
- }
-
- if (cmd->argc == 3) {
- tmp = atoi(cmd->argv[2]);
- SILC_PUT32_MSB(tmp, port);
- }
-
- if (cmd->argc == 3)
- buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 2,
- 1, cmd->argv[1],
- strlen(cmd->argv[1]),
- 2, port, 4);
- else
- buffer = silc_command_payload_encode_va(SILC_COMMAND_CLOSE, 0, 1,
- 1, cmd->argv[1],
- strlen(cmd->argv[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);
-
- /* Notify application */
- COMMAND;
-
- out:
- silc_client_command_free(cmd);
-}
-
-/* SHUTDOWN command. Shutdowns the server. */
-
-SILC_CLIENT_CMD_FUNC(shutdown)
-{
- SilcClientCommandContext cmd = (SilcClientCommandContext)context;
-
- if (!cmd->conn) {
- SILC_NOT_CONNECTED(cmd->client, cmd->conn);
- COMMAND_ERROR;
- goto out;
- }
-
- /* Send the command */
- silc_client_command_send(cmd->client, cmd->conn,
- SILC_COMMAND_SHUTDOWN, 0, 0);
-
- /* Notify application */
- COMMAND;
-
- out:
- silc_client_command_free(cmd);
-}
-
/* LEAVE command. Leaves a channel. Client removes itself from a channel. */
SILC_CLIENT_CMD_FUNC(leave)
return FALSE;
}
+/* Private range commands, specific to this implementation (and compatible
+ with SILC Server). */
+
+/* CONNECT command. Connects the server to another server. */
+
+SILC_CLIENT_CMD_FUNC(connect)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
+ unsigned char port[4];
+ SilcUInt32 tmp;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argc < 2) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Usage: /CONNECT <server> [<port>]");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argc == 3) {
+ tmp = atoi(cmd->argv[2]);
+ SILC_PUT32_MSB(tmp, port);
+ }
+
+ if (cmd->argc == 3)
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 2,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[1]),
+ 2, port, 4);
+ else
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CONNECT, 0, 1,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[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);
+
+ /* Notify application */
+ COMMAND;
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+
+/* CLOSE command. Close server connection to the remote server */
+
+SILC_CLIENT_CMD_FUNC(close)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
+ unsigned char port[4];
+ SilcUInt32 tmp;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argc < 2) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Usage: /CLOSE <server> [<port>]");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argc == 3) {
+ tmp = atoi(cmd->argv[2]);
+ SILC_PUT32_MSB(tmp, port);
+ }
+
+ if (cmd->argc == 3)
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 2,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[1]),
+ 2, port, 4);
+ else
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_PRIV_CLOSE, 0, 1,
+ 1, cmd->argv[1],
+ strlen(cmd->argv[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);
+
+ /* Notify application */
+ COMMAND;
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+/* SHUTDOWN command. Shutdowns the server. */
+
+SILC_CLIENT_CMD_FUNC(shutdown)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ /* Send the command */
+ silc_client_command_send(cmd->client, cmd->conn,
+ SILC_COMMAND_PRIV_SHUTDOWN, 0, 0);
+
+ /* Notify application */
+ COMMAND;
+
+ out:
+ silc_client_command_free(cmd);
+}
+
/* Register all default commands provided by the client library for the
application. */
SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
SILC_CLIENT_CMD(kill, KILL, "KILL", 3);
SILC_CLIENT_CMD(info, INFO, "INFO", 2);
- SILC_CLIENT_CMD(connect, CONNECT, "CONNECT", 3);
SILC_CLIENT_CMD(ping, PING, "PING", 2);
SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 5);
SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
- SILC_CLIENT_CMD(close, CLOSE, "CLOSE", 3);
- SILC_CLIENT_CMD(shutdown, SHUTDOWN, "SHUTDOWN", 1);
SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
SILC_CLIENT_CMD(users, USERS, "USERS", 2);
SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
+
+ SILC_CLIENT_CMD(connect, PRIV_CONNECT, "CONNECT", 3);
+ SILC_CLIENT_CMD(close, PRIV_CLOSE, "CLOSE", 3);
+ SILC_CLIENT_CMD(shutdown, PRIV_SHUTDOWN, "SHUTDOWN", 1);
}
/* Unregister all commands. */
SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
SILC_CLIENT_CMDU(kill, KILL, "KILL");
SILC_CLIENT_CMDU(info, INFO, "INFO");
- SILC_CLIENT_CMDU(connect, CONNECT, "CONNECT");
SILC_CLIENT_CMDU(ping, PING, "PING");
SILC_CLIENT_CMDU(oper, OPER, "OPER");
SILC_CLIENT_CMDU(join, JOIN, "JOIN");
SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
SILC_CLIENT_CMDU(kick, KICK, "KICK");
SILC_CLIENT_CMDU(ban, BAN, "BAN");
- SILC_CLIENT_CMDU(close, CLOSE, "CLOSE");
- SILC_CLIENT_CMDU(shutdown, SHUTDOWN, "SHUTDOWN");
SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
SILC_CLIENT_CMDU(users, USERS, "USERS");
SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
+
+ SILC_CLIENT_CMDU(connect, PRIV_CONNECT, "CONNECT");
+ SILC_CLIENT_CMDU(close, PRIV_CLOSE, "CLOSE");
+ SILC_CLIENT_CMDU(shutdown, PRIV_SHUTDOWN, "SHUTDOWN");
}
silc_client_command_reply_free(cmd);
}
-SILC_CLIENT_CMD_REPLY_FUNC(connect)
-{
- SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
- SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
-
- if (cmd->status != SILC_STATUS_OK) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(cmd->status));
- COMMAND_REPLY_ERROR;
- goto out;
- }
-
- /* Notify application */
- COMMAND_REPLY((ARGS));
-
- out:
- SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CONNECT);
- silc_client_command_reply_free(cmd);
-}
-
SILC_CLIENT_CMD_REPLY_FUNC(ban)
{
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
silc_client_command_reply_free(cmd);
}
-SILC_CLIENT_CMD_REPLY_FUNC(close)
-{
- SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
- SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
-
- if (cmd->status != SILC_STATUS_OK) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(cmd->status));
- COMMAND_REPLY_ERROR;
- goto out;
- }
-
- /* Notify application */
- COMMAND_REPLY((ARGS));
+/* Reply to LEAVE command. */
- out:
- SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_CLOSE);
- silc_client_command_reply_free(cmd);
-}
-
-SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
+SILC_CLIENT_CMD_REPLY_FUNC(leave)
{
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcChannelID *channel_id;
+ SilcChannelEntry channel = NULL;
+ unsigned char *tmp;
+ SilcUInt32 len;
if (cmd->status != SILC_STATUS_OK) {
SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
goto out;
}
- /* Notify application */
- COMMAND_REPLY((ARGS));
-
- out:
- SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_SHUTDOWN);
- silc_client_command_reply_free(cmd);
-}
-
-/* Reply to LEAVE command. */
+ /* From protocol version 1.1 we get the channel ID of the left channel */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (tmp) {
+ channel_id = silc_id_payload_parse_id(tmp, len, NULL);
+ if (!channel_id)
+ goto out;
-SILC_CLIENT_CMD_REPLY_FUNC(leave)
-{
- SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
- SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ /* Get the channel entry */
+ channel = silc_client_get_channel_by_id(cmd->client, conn, channel_id);
+ if (!channel) {
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
- if (cmd->status != SILC_STATUS_OK) {
- SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
- "%s", silc_client_command_status_message(cmd->status));
- COMMAND_REPLY_ERROR;
- goto out;
+ silc_free(channel_id);
}
/* Notify application */
- COMMAND_REPLY((ARGS));
+ COMMAND_REPLY((ARGS, channel));
out:
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_LEAVE);
silc_free(server_id);
silc_client_command_reply_free(cmd);
}
+
+
+/* Private range commands, specific to this implementation (and compatible
+ with SILC Server). */
+
+SILC_CLIENT_CMD_REPLY_FUNC(connect)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ if (cmd->status != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(cmd->status));
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Notify application */
+ COMMAND_REPLY((ARGS));
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CONNECT);
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(close)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ if (cmd->status != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(cmd->status));
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Notify application */
+ COMMAND_REPLY((ARGS));
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_CLOSE);
+ silc_client_command_reply_free(cmd);
+}
+
+SILC_CLIENT_CMD_REPLY_FUNC(shutdown)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+
+ if (cmd->status != SILC_STATUS_OK) {
+ SAY(cmd->client, conn, SILC_CLIENT_MESSAGE_ERROR,
+ "%s", silc_client_command_status_message(cmd->status));
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Notify application */
+ COMMAND_REPLY((ARGS));
+
+ out:
+ SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_PRIV_SHUTDOWN);
+ silc_client_command_reply_free(cmd);
+}
+
`msg' maybe NULL. */
void (*channel_message)(SilcClient client, SilcClientConnection conn,
SilcClientEntry sender, SilcChannelEntry channel,
- SilcMessageFlags flags, char *msg);
+ SilcMessageFlags flags,
+ const unsigned char *message,
+ SilcUInt32 message_len);
/* Private message to the client. The `sender' is the sender of the
message. */
void (*private_message)(SilcClient client, SilcClientConnection conn,
SilcClientEntry sender, SilcMessageFlags flags,
- char *msg);
+ const unsigned char *message,
+ SilcUInt32 message_len);
/* Notify message to the client. The notify arguments are sent in the
same order as servers sends them. The arguments are same as received
#define SILC_MESSAGE_FLAG_NOTICE 0x0008
#define SILC_MESSAGE_FLAG_REQUEST 0x0010
#define SILC_MESSAGE_FLAG_SIGNED 0x0020
-#define SILC_MESSAGE_FLAG_RESERVED 0x0040 /* to 0x0200 */
-#define SILC_MESSAGE_FLAG_PRIVATE 0x0400 /* to 0x8000 */
+#define SILC_MESSAGE_FLAG_REPLY 0x0040
+#define SILC_MESSAGE_FLAG_DATA 0x0080
+#define SILC_MESSAGE_FLAG_RESERVED 0x0100 /* to 0x0800 */
+#define SILC_MESSAGE_FLAG_PRIVATE 0x1000 /* to 0x8000 */
/***/
/* Prototypes */
#define SILC_COMMAND_QUIT 8
#define SILC_COMMAND_KILL 9
#define SILC_COMMAND_INFO 10
-#define SILC_COMMAND_CONNECT 11
#define SILC_COMMAND_PING 12
#define SILC_COMMAND_OPER 13
#define SILC_COMMAND_JOIN 14
#define SILC_COMMAND_CUMODE 18
#define SILC_COMMAND_KICK 19
#define SILC_COMMAND_BAN 20
-#define SILC_COMMAND_CLOSE 21
-#define SILC_COMMAND_SHUTDOWN 22
#define SILC_COMMAND_SILCOPER 23
#define SILC_COMMAND_LEAVE 24
#define SILC_COMMAND_USERS 25
#define SILC_COMMAND_GETKEY 26
+/* Private range start */
+#define SILC_COMMAND_PRIV_CONNECT 200
+#define SILC_COMMAND_PRIV_CLOSE 201
+#define SILC_COMMAND_PRIV_SHUTDOWN 202
+
/* Reserved */
#define SILC_COMMAND_RESERVED 255
/***/
#define SILC_CHANNEL_MODE_CIPHER 0x0080 /* sets cipher of the channel */
#define SILC_CHANNEL_MODE_HMAC 0x0100 /* sets hmac of the channel */
#define SILC_CHANNEL_MODE_FOUNDER_AUTH 0x0200 /* sets founder auth data */
+#define SILC_CHANNEL_MODE_SILENCE_USERS 0x0400 /* sets founder auth data */
+#define SILC_CHANNEL_MODE_SILENCE_OPERS 0x0800 /* sets founder auth data */
/***/
/****d* silccore/Modes/ChannelUserModes
if (mode & SILC_CHANNEL_MODE_FOUNDER_AUTH)
strncat(string, "f", 1);
+ if (mode & SILC_CHANNEL_MODE_SILENCE_USERS)
+ strncat(string, "m", 1);
+
+ if (mode & SILC_CHANNEL_MODE_SILENCE_OPERS)
+ strncat(string, "M", 1);
+
if (mode & SILC_CHANNEL_MODE_CIPHER)
strncat(string, cipher, strlen(cipher));
echo "/* Automatically generated by ./prepare */" >$file
echo "#define SILC_VERSION_STRING \"$version\"" >>$file
echo "#define SILC_DIST_VERSION_STRING \"$dist_version\"" >>$file
-echo "#define SILC_PROTOCOL_VERSION_STRING \"SILC-1.0-$version\"" >>$file
+echo "#define SILC_PROTOCOL_VERSION_STRING \"SILC-1.1-$version\"" >>$file
echo "#define SILC_NAME \"SILC $distribution\"" >>$file
# preparing irssi