+Mon Mar 26 12:11:14 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added silc_server_send_notify_invite to send the INVITE
+ notify between routers.
+
+ * Implemented the INVITE command correctly to the server.
+
+ * Implemented the INVITE notify type handling in the server.
+
+ * Implemented the INVITE command to the client library and on the
+ user interface.
+
Sun Mar 25 20:27:09 EEST 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Added function silc_server_get_client_resolve to find the
Gives a little history information about a client.
+ /INVITE <channel> [<nickname>[@server>]
+ [+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]
+
+ Invites client to a channel or manages the invite list of
+ the channel. The first <nickname> argument is used if an
+ client is invited to the channel. The second +|-<nickname>
+ argument is used to either add or delete invite from the
+ channel's invite list. Wildcards may be used with this
+ command.
+
+ /BAN <channel> [+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]
+
+ Manages the ban list of the channel. Wildcards may be used
+ with this command. You must be channel operator to be
+ able to use this command.
+
/KICK <channel> <nickname>[@<server>] [<comment>]
Kicks client from channel. You have to be at least channel
TODO In SILC Server
===================
- o TODO in command.c and in command_reply.c:
+ o TODO in commands (command.c and command_reply.c):
- o BAN is not implemented
o RESTART is not implemented
- o INVITE is not working correctly
- 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
the wrong way.
situation correctly when it is called as pending command
(it should most likely check that cmd->pending == TRUE/FALSE).
- o Implement the SILC_NOTIFY_TYPE_SERVER_QUIT notify type to the server.
+ o TODO in notify types (packet_receive.c):
+
+ o CHANNEL_CHANGE notify type is not implemented
+ o SERVER_SIGNOFF notify type is not implemented
o Packet processing can be made faster. All packet function in the
packet_receive.c has same prototypes. Instead of calling those from
break;
case SILC_NOTIFY_TYPE_INVITE:
+ (void)va_arg(vp, SilcChannelEntry);
+ tmp = va_arg(vp, char *);
client_entry = va_arg(vp, SilcClientEntry);
- channel_entry = va_arg(vp, SilcChannelEntry);
snprintf(message, sizeof(message), "%s invites you to channel %s",
- client_entry->nickname, channel_entry->channel_name);
+ client_entry->nickname, tmp);
break;
case SILC_NOTIFY_TYPE_JOIN:
}
break;
+ case SILC_COMMAND_INVITE:
+ {
+ SilcChannelEntry channel;
+ char *invite_list;
+
+ if (!success)
+ return;
+
+ channel = va_arg(vp, SilcChannelEntry);
+ invite_list = va_arg(vp, char *);
+
+ if (invite_list)
+ silc_say(client, conn, "%s invite list: %s", channel->channel_name,
+ invite_list);
+ else
+ silc_say(client, conn, "%s invite list not set",
+ channel->channel_name);
+ }
+ break;
+
case SILC_COMMAND_JOIN:
{
unsigned int mode;
SilcChannelEntry channel;
SilcChannelID *channel_id = NULL;
SilcIDListData idata;
- SilcBuffer idp;
+ SilcBuffer idp, idp2, packet;
unsigned char *tmp, *add, *del;
unsigned int len;
+ unsigned short ident = silc_command_get_ident(cmd->payload);
- SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 2);
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_INVITE, cmd, 1, 4);
/* Get Channel ID */
tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
}
/* Get route to the client */
- dest_sock = silc_server_get_client_route(server, tmp, len, &idata);
+ dest_sock = silc_server_get_client_route(server, NULL, 0, dest_id, &idata);
+ memset(invite, 0, sizeof(invite));
strncat(invite, dest->nickname, strlen(dest->nickname));
- if (!strchr(dest->nickname, '@')) {
- strncat(invite, "@", 1);
- strncat(invite, server->server_name, strlen(server->server_name));
- }
strncat(invite, "!", 1);
strncat(invite, dest->username, strlen(dest->username));
if (!strchr(dest->username, '@')) {
channel->invite_list = silc_calloc(len + 2,
sizeof(*channel->invite_list));
else
- channel->invite_list = silc_realloc(channel->ban_list,
+ channel->invite_list = silc_realloc(channel->invite_list,
sizeof(*channel->invite_list) *
(len +
strlen(channel->invite_list) + 2));
strncat(channel->invite_list, ",", 1);
/* Send notify to the client that is invited to the channel */
- idp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
- tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
+ idp2 = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
silc_server_send_notify_dest(server, dest_sock, FALSE, dest_id,
SILC_ID_CLIENT,
- SILC_NOTIFY_TYPE_INVITE, 2,
- idp->data, idp->len, tmp, len);
+ SILC_NOTIFY_TYPE_INVITE, 3,
+ idp->data, idp->len,
+ channel->channel_name,
+ strlen(channel->channel_name),
+ idp2->data, idp2->len);
silc_buffer_free(idp);
+ silc_buffer_free(idp2);
}
/* Add the client to the invite list of the channel */
add = silc_argument_get_arg_type(cmd->args, 3, &len);
- if (add && strlen(add) == len) {
+ if (add) {
if (!channel->invite_list)
channel->invite_list = silc_calloc(len + 2,
sizeof(*channel->invite_list));
else
- channel->invite_list = silc_realloc(channel->ban_list,
+ channel->invite_list = silc_realloc(channel->invite_list,
sizeof(*channel->invite_list) *
(len +
strlen(channel->invite_list) + 2));
strlen(channel->invite_list) - 1)) {
silc_free(channel->invite_list);
channel->invite_list = NULL;
- goto out0;
- }
-
- start = strstr(channel->invite_list, del);
- if (start && strlen(start) >= len) {
- end = start + len;
- n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
- strncat(n, channel->invite_list, start - channel->invite_list);
- strncat(n, end + 1, ((channel->invite_list +
- strlen(channel->invite_list)) - end) - 1);
- silc_free(channel->invite_list);
- channel->invite_list = n;
+ } else {
+ start = strstr(channel->invite_list, del);
+ if (start && strlen(start) >= len) {
+ end = start + len;
+ n = silc_calloc(strlen(channel->invite_list) - len, sizeof(*n));
+ strncat(n, channel->invite_list, start - channel->invite_list);
+ strncat(n, end + 1, ((channel->invite_list +
+ strlen(channel->invite_list)) - end) - 1);
+ silc_free(channel->invite_list);
+ channel->invite_list = n;
+ }
}
}
- out0:
-
- idp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
-
/* Send notify to the primary router */
-
+ if (!server->standalone)
+ silc_server_send_notify_invite(server, server->router->connection,
+ server->server_type == SILC_ROUTER ?
+ TRUE : FALSE, channel,
+ sender->id, SILC_ID_CLIENT_LEN,
+ add, del);
/* Send command reply */
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
- SILC_STATUS_OK);
-
- silc_buffer_free(idp);
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INVITE,
+ SILC_STATUS_OK, ident, 2,
+ 2, tmp, len,
+ 3, channel->invite_list,
+ channel->invite_list ?
+ strlen(channel->invite_list) :
+ 0);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
out:
if (dest_id)
/* Check invite list if channel is invite-only channel */
if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT &&
- channel->mode & SILC_CHANNEL_MODE_INVITE && channel->invite_list) {
+ channel->mode & SILC_CHANNEL_MODE_INVITE) {
+ if (!channel->invite_list) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_INVITED);
+ goto out;
+ }
+
if (!silc_string_match(channel->invite_list, check)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_NOT_INVITED);
/* Get the new ban and add it to the ban list */
add = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
- if (add && strlen(add) == tmp_len) {
+ if (add) {
if (!channel->ban_list)
channel->ban_list = silc_calloc(tmp_len + 2, sizeof(*channel->ban_list));
else
if (!strncmp(channel->ban_list, del, strlen(channel->ban_list) - 1)) {
silc_free(channel->ban_list);
channel->ban_list = NULL;
- goto out0;
- }
-
- start = strstr(channel->ban_list, del);
- if (start && strlen(start) >= tmp_len) {
- end = start + tmp_len;
- n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
- strncat(n, channel->ban_list, start - channel->ban_list);
- strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) -
- end) - 1);
- silc_free(channel->ban_list);
- channel->ban_list = n;
+ } else {
+ start = strstr(channel->ban_list, del);
+ if (start && strlen(start) >= tmp_len) {
+ end = start + tmp_len;
+ n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
+ strncat(n, channel->ban_list, start - channel->ban_list);
+ strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) -
+ end) - 1);
+ silc_free(channel->ban_list);
+ channel->ban_list = n;
+ }
}
}
- out0:
-
/* Send the BAN notify type to our primary router. */
if (!server->standalone && (add || del))
silc_server_send_notify_ban(server, server->router->connection,
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, &idata);
+ packet->dst_id_len, NULL, &idata);
if (dst_sock)
/* Relay the packet */
silc_server_relay_packet(server, dst_sock, idata->send_key,
break;
case SILC_NOTIFY_TYPE_INVITE:
- SILC_LOG_DEBUG(("INVITE notify (not-impl XXX)"));
+
+ if (packet->dst_id_type == SILC_ID_CLIENT)
+ goto out;
+
+ SILC_LOG_DEBUG(("INVITE notify"));
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel) {
+ silc_free(channel_id);
+ goto out;
+ }
+ }
+ silc_free(channel_id);
+
+ /* Get the added invite */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (tmp) {
+ if (!channel->invite_list)
+ channel->invite_list = silc_calloc(tmp_len + 2,
+ sizeof(*channel->invite_list));
+ else
+ channel->invite_list = silc_realloc(channel->invite_list,
+ sizeof(*channel->invite_list) *
+ (tmp_len +
+ strlen(channel->invite_list) +
+ 2));
+ if (tmp[tmp_len - 1] == ',')
+ tmp[tmp_len - 1] = '\0';
+
+ strncat(channel->invite_list, tmp, tmp_len);
+ strncat(channel->invite_list, ",", 1);
+ }
+
+ /* Get the deleted invite */
+ tmp = silc_argument_get_arg_type(args, 4, &tmp_len);
+ if (tmp && channel->invite_list) {
+ char *start, *end, *n;
+
+ if (!strncmp(channel->invite_list, tmp,
+ strlen(channel->invite_list) - 1)) {
+ silc_free(channel->invite_list);
+ channel->invite_list = NULL;
+ } else {
+ start = strstr(channel->invite_list, tmp);
+ if (start && strlen(start) >= tmp_len) {
+ end = start + tmp_len;
+ n = silc_calloc(strlen(channel->invite_list) - tmp_len, sizeof(*n));
+ strncat(n, channel->invite_list, start - channel->invite_list);
+ strncat(n, end + 1, ((channel->invite_list +
+ strlen(channel->invite_list)) - end) - 1);
+ silc_free(channel->invite_list);
+ channel->invite_list = n;
+ }
+ }
+ }
+
break;
case SILC_NOTIFY_TYPE_CHANNEL_CHANGE:
if (!strcmp(channel->ban_list, tmp)) {
silc_free(channel->ban_list);
channel->ban_list = NULL;
- break;
- }
-
- start = strstr(channel->ban_list, tmp);
- if (start && strlen(start) >= tmp_len) {
- end = start + tmp_len;
- n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
- strncat(n, channel->ban_list, start - channel->ban_list);
- strncat(n, end + 1, ((channel->ban_list + strlen(channel->ban_list)) -
- end) - 1);
- silc_free(channel->ban_list);
- channel->ban_list = n;
+ } else {
+ start = strstr(channel->ban_list, tmp);
+ if (start && strlen(start) >= tmp_len) {
+ end = start + tmp_len;
+ n = silc_calloc(strlen(channel->ban_list) - tmp_len, sizeof(*n));
+ strncat(n, channel->ban_list, start - channel->ban_list);
+ strncat(n, end + 1, ((channel->ban_list +
+ strlen(channel->ban_list)) - end) - 1);
+ silc_free(channel->ban_list);
+ channel->ban_list = n;
+ }
}
}
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, &idata);
+ packet->dst_id_len, NULL, &idata);
if (!dst_sock)
return;
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, &idata);
+ packet->dst_id_len, NULL, &idata);
if (!dst_sock)
return;
/* Get the route to the client */
dst_sock = silc_server_get_client_route(server, packet->dst_id,
- packet->dst_id_len, &idata);
+ packet->dst_id_len, NULL, &idata);
if (!dst_sock)
return;
silc_buffer_free(idp);
}
-/* Sends BAN notify type. This tells that `ban' has been either `add'ed
+/* Sends BAN notify type. This tells that ban has been either `add'ed
or `del'eted on the `channel. This function is used to send the packet
between routers as broadcast packet. */
silc_buffer_free(idp);
}
+/* Sends INVITE notify type. This tells that invite has been either `add'ed
+ or `del'eted on the `channel. The sender of the invite is the `client_id'.
+ This function is used to send the packet between routers as broadcast
+ packet. */
+
+void silc_server_send_notify_invite(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ unsigned int client_id_len,
+ char *add, char *del)
+{
+ SilcBuffer idp, idp2;
+
+ idp = silc_id_payload_encode((void *)channel->id, SILC_ID_CHANNEL);
+ idp2 = silc_id_payload_encode((void *)client_id, SILC_ID_CLIENT);
+ silc_server_send_notify(server, sock, broadcast,
+ SILC_NOTIFY_TYPE_INVITE, 5,
+ idp->data, idp->len,
+ channel->channel_name, strlen(channel->channel_name),
+ idp2->data, idp2->len,
+ add, add ? strlen(add) : 0,
+ del, del ? strlen(del) : 0);
+ silc_buffer_free(idp);
+ silc_buffer_free(idp2);
+}
+
/* Sends notify message destined to specific entity. */
void silc_server_send_notify_dest(SilcServer server,
int broadcast,
SilcChannelEntry channel,
char *add, char *del);
+void silc_server_send_notify_invite(SilcServer server,
+ SilcSocketConnection sock,
+ int broadcast,
+ SilcChannelEntry channel,
+ SilcClientID *client_id,
+ unsigned int client_id_len,
+ char *add, char *del);
void silc_server_send_notify_dest(SilcServer server,
SilcSocketConnection sock,
int broadcast,
/* Lookups route to the client indicated by `id' client ID. The connection
object and internal data object is returned. Returns NULL if route
- could not be found to the client. */
+ could not be found to the client. If the `client_id' is specified then
+ it is used and the `id_data' is ignored. */
SilcSocketConnection silc_server_get_client_route(SilcServer server,
unsigned char *id_data,
unsigned int id_len,
+ SilcClientID *client_id,
SilcIDListData *idata)
{
SilcClientID *id;
SILC_LOG_DEBUG(("Start"));
/* Decode destination Client ID */
- id = silc_id_str2id(id_data, id_len, SILC_ID_CLIENT);
- if (!id) {
- SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
- return NULL;
+ if (!client_id) {
+ id = silc_id_str2id(id_data, id_len, SILC_ID_CLIENT);
+ if (!id) {
+ SILC_LOG_ERROR(("Could not decode destination Client ID, dropped"));
+ return NULL;
+ }
+ } else {
+ id = silc_id_dup(client_id, SILC_ID_CLIENT);
}
/* If the destination belongs to our server we don't have to route
SilcSocketConnection silc_server_get_client_route(SilcServer server,
unsigned char *id_data,
unsigned int id_len,
+ SilcClientID *client_id,
SilcIDListData *idata);
SilcBuffer silc_server_get_client_channel_list(SilcServer server,
SilcClientEntry client);
[Cipher]
-aes-256-cbc:../lib/silcsim/modules/aes.sim.so:32:16
-aes-192-cbc:../lib/silcsim/modules/aes.sim.so:24:16
-aes-128-cbc:../lib/silcsim/modules/aes.sim.so:16:16
-twofish-256-cbc:../lib/silcsim/modules/twofish.sim.so:32:16
-twofish-192-cbc:../lib/silcsim/modules/twofish.sim.so:24:16
-twofish-128-cbc:../lib/silcsim/modules/twofish.sim.so:16:16
-mars-256-cbc:../lib/silcsim/modules/mars.sim.so:32:16
-mars-192-cbc:../lib/silcsim/modules/mars.sim.so:24:16
-mars-128-cbc:../lib/silcsim/modules/mars.sim.so:16:16
+rc6:../lib/silcsim/modules/rc6.sim.so:16:16
+twofish:../lib/silcsim/modules/twofish.sim.so:16:16
+mars:../lib/silcsim/modules/mars.sim.so:16:16
none:../lib/silcsim/modules/none.sim.so:0:0
-[Hash]
+[Hash]
md5::64:16
sha1::64:20
[hmac]
hmac-sha1-96:sha1:12
hmac-md5-96:md5:12
-hmac-sha1:sha1:20
+hmac-sha1:sha1:20
hmac-md5:md5:16
#[PKCS]
Mun huone:Mun servo:Pekka Riikonen:priikone@poseidon.pspt.fi
[ServerInfo]
-lassi.kuo.fi.ssh.com:212.146.42.253:Kuopio, Finland:1334
+lassi.kuo.fi.ssh.com:10.2.1.7:Kuopio, Finland:1334
[ListenPort]
-212.146.42.253:212.146.42.253:1334
+10.2.1.7:10.2.1.7:1334
[Logging]
infologfile:silcd2.log:10000
:::1336:1
[AdminConnection]
-*:priikone:*:passwd:testi
+*:silc:silc:passwd:testi
[ServerConnection]
-212.146.42.253:passwd:priikone:1333: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
Sent when an client is invited to a channel. This is also sent
when the invite list of the channel is changed. This notify type
is sent between routers and if the <Client ID> is argument is
- provided to the client as well.
+ provided to the client as well. In this case the packet is
+ destined to the client.
Max Arguments: 5
- Arguments: (1) <Channel ID> (2) [<Client ID>]
- (3) [<sender Client ID>] (3) [<adding client>]
- (4) [<removing client>]
-
- The <Client ID> is the client which was invited to the channel.
- The <Channel ID> is the channel. The <sender Client ID> is the
+ Arguments: (1) <Channel ID> (2) <channel name>
+ (3) [<sender Client ID>] (4) [<adding client>]
+ (5) [<removing client>]
+
+ The <Channel ID> is the channel. The <channel name> is the name
+ of the channel and is provided because the client which receives
+ this notify packet may not have a way to resolve the name of the
+ channel from the <Channel ID>. The <sender Client ID> is the
Client ID who invited the client to the channel. The <adding client>
- and the <removing client> indicates the added or removed client from
- the channel's invite list. The format of the <adding client and the
- <removing client> is defined in the [SILC1] with SILC_COMMAND_INVITE
- command.
+ and the <removing client> indicates the added or removed client
+ from the channel's invite list. The format of the <adding client
+ and the <removing client> is defined in the [SILC1] with
+ SILC_COMMAND_INVITE command.
The <adding client> and <removing client> is never sent to the
- client indicated by the <Client ID>. Also note that the lists
- include the <Client ID> already.
+ client indicated by the <Client ID>.
2 SILC_NOTIFY_TYPE_JOIN
10 SILC_NOTIFY_TYPE_CHANNEL_CHANGE
Sent when channel's ID has changed for a reason or another. This
- is sent by noral server to the client. Client must change the
+ is sent by normal server to the client. Client must change the
old Channel ID to the new one. This type must be sent only to the
clients who is joined on the channel.
Reply messages to the command:
- Max Arguments: 2
- Arguments: (1) <Status Payload>
+ Max Arguments: 3
+ Arguments: (1) <Status Payload> (2) <Channel ID>
+ (3) [<invite list>]
- This command replies only with Status Payload.
+ This command replies with the invite list of the channel if it
+ exists.
Status messages:
* for the application.
*/
- /* Get Client ID */
+ /* Get Channel ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
if (!tmp)
goto out;
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+ if (!channel_id)
+ goto out;
+
+ /* Get the channel entry */
+ channel = NULL;
+ if (silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache))
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Get sender Client ID */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp)
+ goto out;
+
client_id = silc_id_payload_parse_id(tmp, tmp_len);
if (!client_id)
goto out;
goto out;
}
- /* Get Channel ID */
+ /* Get the channel name */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
if (!tmp)
goto out;
- channel_id = silc_id_payload_parse_id(tmp, tmp_len);
- if (!channel_id)
- goto out;
-
- /* XXX Will ALWAYS fail because currently we don't have way to resolve
- channel information for channel that we're not joined to. */
- /* XXX ways to fix: use (extended) LIST command, or define the channel
- name to the notfy type when name resolving is not mandatory. */
- /* Find channel entry */
- if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
- SILC_ID_CHANNEL, &id_cache))
- goto out;
-
- channel = (SilcChannelEntry)id_cache->context;
-
/* Notify application */
- client->ops->notify(client, conn, type, client_entry, channel);
+ client->ops->notify(client, conn, type, channel, tmp, client_entry);
break;
case SILC_NOTIFY_TYPE_JOIN:
silc_client_command_free(cmd);
}
-/* Command INVITE. Invites specific client to join a channel. */
+/* Command INVITE. Invites specific client to join a channel. This is
+ also used to mange the invite list of the channel. */
SILC_CLIENT_CMD_FUNC(invite)
{
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClient client = cmd->client;
SilcClientConnection conn = cmd->conn;
- SilcClientEntry client_entry;
- SilcChannelEntry channel_entry;
+ SilcClientEntry client_entry = NULL;
+ SilcChannelEntry channel;
SilcBuffer buffer, clidp, chidp;
- unsigned int num = 0;
- char *nickname = NULL, *server = NULL;
+ unsigned int num = 0, type = 0;
+ char *nickname = NULL, *server = NULL, *name;
+ char *invite = NULL;
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
goto out;
}
- if (cmd->argc != 3) {
+ if (cmd->argc < 2) {
cmd->client->ops->say(cmd->client, conn,
- "Usage: /INVITE <nickname>[@<server>] <channel>");
+ "Usage: /INVITE <channel> [<nickname>[@server>]"
+ "[+|-[<nickname>[@<server>[!<username>[@hostname>]]]]]");
COMMAND_ERROR;
goto out;
}
- /* Parse the typed nickname. */
- if (!silc_parse_nickname(cmd->argv[1], &nickname, &server, &num)) {
- cmd->client->ops->say(cmd->client, conn, "Bad nickname");
- COMMAND_ERROR;
- goto out;
- }
+ if (cmd->argv[1][0] == '*') {
+ if (!conn->current_channel) {
+ cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+ COMMAND_ERROR;
+ goto out;
+ }
- /* Find client entry */
- client_entry = silc_idlist_get_client(client, conn, nickname, server, num,
- TRUE);
- if (!client_entry) {
- if (nickname)
- silc_free(nickname);
- if (server)
- silc_free(server);
+ channel = conn->current_channel;
+ } else {
+ name = cmd->argv[1];
- /* Client entry not found, it was requested thus mark this to be
- pending command. */
- silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY, conn->cmd_ident,
- silc_client_command_destructor,
- silc_client_command_invite,
- silc_client_command_dup(cmd));
- cmd->pending = 1;
- return;
+ channel = silc_client_get_channel(cmd->client, conn, name);
+ if (!channel) {
+ cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+ COMMAND_ERROR;
+ goto out;
+ }
}
- /* Find channel entry */
- channel_entry = silc_client_get_channel(client, conn, cmd->argv[2]);
- if (!channel_entry) {
- cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
- COMMAND_ERROR;
- goto out;
+ /* Parse the typed nickname. */
+ if (cmd->argc == 3) {
+ if (cmd->argv[2][0] != '+' && cmd->argv[2][0] != '-') {
+ if (!silc_parse_nickname(cmd->argv[2], &nickname, &server, &num)) {
+ cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ /* Find client entry */
+ client_entry = silc_idlist_get_client(client, conn, nickname,
+ server, num, TRUE);
+ if (!client_entry) {
+ if (nickname)
+ silc_free(nickname);
+ if (server)
+ silc_free(server);
+
+ if (cmd->pending) {
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ /* Client entry not found, it was requested thus mark this to be
+ pending command. */
+ silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
+ conn->cmd_ident,
+ silc_client_command_destructor,
+ silc_client_command_invite,
+ silc_client_command_dup(cmd));
+ cmd->pending = 1;
+ return;
+ }
+
+ cmd->client->ops->say(cmd->client, conn,
+ "Inviting %s to channel %s", cmd->argv[2],
+ channel->channel_name);
+ } else {
+ invite = cmd->argv[2];
+ invite++;
+ if (cmd->argv[2][0] == '+')
+ type = 3;
+ else
+ type = 4;
+ }
+ }
+
+ /* Send the command */
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ if (client_entry) {
+ clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
+ ++conn->cmd_ident, 3,
+ 1, chidp->data, chidp->len,
+ 2, clidp->data, clidp->len,
+ type, invite, invite ?
+ strlen(invite) : 0);
+ silc_buffer_free(clidp);
+ } else {
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE,
+ ++conn->cmd_ident, 2,
+ 1, chidp->data, chidp->len,
+ type, invite, invite ?
+ strlen(invite) : 0);
}
- /* Send command */
- clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
- chidp = silc_id_payload_encode(channel_entry->id, SILC_ID_CHANNEL);
- buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 0, 2,
- 1, clidp->data, clidp->len,
- 2, chidp->data, chidp->len);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- silc_buffer_free(clidp);
silc_buffer_free(chidp);
- cmd->client->ops->say(cmd->client, conn,
- "Inviting %s to channel %s", cmd->argv[1],
- cmd->argv[2]);
-
/* Notify application */
COMMAND;
if (server)
silc_free(server);
+ if (cmd->pending) {
+ COMMAND_ERROR;
+ goto out;
+ }
+
/* Client entry not found, it was requested thus mark this to be
pending command. */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
client_entry = silc_idlist_get_client(cmd->client, conn,
nickname, server, num, TRUE);
if (!client_entry) {
+ if (cmd->pending) {
+ COMMAND_ERROR;
+ goto out;
+ }
+
/* Client entry not found, it was requested thus mark this to be
pending command. */
silc_client_command_pending(conn, SILC_COMMAND_IDENTIFY,
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcCommandStatus status;
+ SilcChannelEntry channel;
+ SilcChannelID *channel_id;
+ SilcIDCacheEntry id_cache;
unsigned char *tmp;
+ unsigned int len;
tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
SILC_GET16_MSB(status, tmp);
return;
}
+ /* Take Channel ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
+ goto out;
+
+ channel_id = silc_id_payload_parse_id(tmp, len);
+ if (!channel_id)
+ goto out;
+
+ /* Get the channel entry */
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache)) {
+ silc_free(channel_id);
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Get the invite list */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+
/* Notify application */
- COMMAND_REPLY((ARGS));
+ COMMAND_REPLY((ARGS, channel, tmp));
/* Execute any pending command callbacks */
SILC_CLIENT_PENDING_EXEC(cmd, SILC_COMMAND_INVITE);
+ out:
SILC_CLIENT_PENDING_DESTRUCTOR(cmd, SILC_COMMAND_INVITE);
silc_client_command_reply_free(cmd);
}