+Fri Feb 23 11:22:57 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Added support for quit message that client can "leave" on the
+ channel when it quits the SILC. It is ditributed inside the
+ SILC_NOTIFY_TYPE_SIGNOFF notify type.
+
+ Added silc_server_free_client_data that will take the
+ signoff message as argument.
+
Thu Feb 22 23:05:36 EET 2001 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Updated parts of the protocol specification to keep it up
char message[4096];
SilcClientEntry client_entry, client_entry2;
SilcChannelEntry channel_entry;
- char *tmp;
+ char *tmp = NULL;
unsigned int tmp_int;
va_start(vp, type);
case SILC_NOTIFY_TYPE_SIGNOFF:
client_entry = va_arg(vp, SilcClientEntry);
+ tmp = va_arg(vp, char *);
if (client_entry->server)
- snprintf(message, sizeof(message), "Signoff: %s@%s",
- client_entry->nickname, client_entry->server);
+ snprintf(message, sizeof(message), "Signoff: %s@%s %s%s%s",
+ client_entry->nickname, client_entry->server,
+ tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
else
- snprintf(message, sizeof(message), "Signoff: %s",
- client_entry->nickname);
+ snprintf(message, sizeof(message), "Signoff: %s %s%s%s",
+ client_entry->nickname,
+ tmp ? "(" : "", tmp ? tmp : "", tmp ? ")" : "");
break;
case SILC_NOTIFY_TYPE_TOPIC_SET:
silc_server_command_free(cmd);
}
+typedef struct {
+ SilcServer server;
+ SilcSocketConnection sock;
+ char *signoff;
+} *QuitInternal;
+
/* Quits connection to client. This gets called if client won't
close the connection even when it has issued QUIT command. */
SILC_TASK_CALLBACK(silc_server_command_quit_cb)
{
- SilcServer server = (SilcServer)context;
- SilcSocketConnection sock = server->sockets[fd];
+ QuitInternal q = (QuitInternal)context;
/* Free all client specific data, such as client entry and entires
on channels this client may be on. */
- silc_server_free_sock_user_data(server, sock);
+ silc_server_free_client_data(q->server, q->sock, q->sock->user_data,
+ q->signoff);
+ q->sock->user_data = NULL;
/* Close the connection on our side */
- silc_server_close_connection(server, sock);
+ silc_server_close_connection(q->server, q->sock);
+
+ silc_free(q->signoff);
+ silc_free(q);
}
/* Quits SILC session. This is the normal way to disconnect client. */
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcSocketConnection sock = cmd->sock;
+ QuitInternal q;
+ unsigned char *tmp = NULL;
+ unsigned int len = 0;
- SILC_LOG_DEBUG(("Start"));
+ SILC_SERVER_COMMAND_CHECK_ARGC(SILC_COMMAND_QUIT, cmd, 0, 1);
+
+ /* Get destination ID */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (len > 128)
+ tmp = NULL;
+
+ q = silc_calloc(1, sizeof(*q));
+ q->server = server;
+ q->sock = sock;
+ q->signoff = tmp ? strdup(tmp) : NULL;
/* We quit the connection with little timeout */
silc_task_register(server->timeout_queue, sock->sock,
- silc_server_command_quit_cb, server,
- 0, 300000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
+ silc_server_command_quit_cb, (void *)q,
+ 0, 200000, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW);
silc_server_command_free(cmd);
}
}
silc_free(client_id);
+ /* Get signoff message */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp_len > 128)
+ tmp = NULL;
+
/* Remove the client from all channels */
- silc_server_remove_from_channels(server, NULL, client);
+ silc_server_remove_from_channels(server, NULL, client, tmp);
/* Remove the client entry */
if (!silc_idlist_del_client(server->global_list, client))
silc_server_close_connection(server, sock);
}
-/* Free's user_data pointer from socket connection object. This also sends
+/* Frees client data and notifies about client's signoff. */
+
+void silc_server_free_client_data(SilcServer server,
+ SilcSocketConnection sock,
+ SilcClientEntry user_data, char *signoff)
+{
+ /* Send REMOVE_ID packet to routers. */
+ if (!server->standalone && server->router)
+ silc_server_send_notify_signoff(server, server->router->connection,
+ server->server_type == SILC_SERVER ?
+ FALSE : TRUE, user_data->id,
+ SILC_ID_CLIENT_LEN, signoff);
+
+ /* Remove client from all channels */
+ silc_server_remove_from_channels(server, sock, user_data, signoff);
+
+ /* XXX must take some info to history before freeing */
+
+ /* Free the client entry and everything in it */
+ silc_idlist_del_data(user_data);
+ silc_idlist_del_client(server->local_list, user_data);
+ server->stat.my_clients--;
+ server->stat.clients--;
+ if (server->server_type == SILC_ROUTER)
+ server->stat.cell_clients--;
+}
+
+/* Frees user_data pointer from socket connection object. This also sends
appropriate notify packets to the network to inform about leaving
entities. */
case SILC_SOCKET_TYPE_CLIENT:
{
SilcClientEntry user_data = (SilcClientEntry)sock->user_data;
-
- /* Send REMOVE_ID packet to routers. */
- if (!server->standalone && server->router)
- silc_server_send_notify_signoff(server, server->router->connection,
- server->server_type == SILC_SERVER ?
- FALSE : TRUE, user_data->id,
- SILC_ID_CLIENT_LEN, NULL);
-
- /* Remove client from all channels */
- silc_server_remove_from_channels(server, sock, user_data);
-
- /* XXX must take some info to history before freeing */
-
- /* Free the client entry and everything in it */
- silc_idlist_del_data(user_data);
- silc_idlist_del_client(server->local_list, user_data);
- server->stat.my_clients--;
- server->stat.clients--;
- if (server->server_type == SILC_ROUTER)
- server->stat.cell_clients--;
+ silc_server_free_client_data(server, sock, user_data, NULL);
break;
}
case SILC_SOCKET_TYPE_SERVER:
}
/* Remove the client entry */
- silc_server_remove_from_channels(server, NULL, client);
+ silc_server_remove_from_channels(server, NULL, client, NULL);
silc_idlist_del_client(server->local_list, client);
if (!silc_idcache_list_next(list, &id_cache))
}
/* Remove the client entry */
- silc_server_remove_from_channels(server, NULL, client);
+ silc_server_remove_from_channels(server, NULL, client, NULL);
silc_idlist_del_client(server->global_list, client);
if (!silc_idcache_list_next(list, &id_cache))
void silc_server_remove_from_channels(SilcServer server,
SilcSocketConnection sock,
- SilcClientEntry client)
+ SilcClientEntry client,
+ char *signoff_message)
{
SilcChannelEntry channel;
SilcChannelClientEntry chl;
/* Notify about leaving client if this channel has global users. */
if (channel->global_users)
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_SIGNOFF, 1,
- clidp->data, clidp->len);
+ SILC_NOTIFY_TYPE_SIGNOFF,
+ signoff_message ? 2 : 1,
+ clidp->data, clidp->len,
+ signoff_message, signoff_message ?
+ strlen(signoff_message) : 0);
if (!silc_idlist_del_channel(server->local_list, channel))
silc_idlist_del_channel(server->global_list, channel);
/* Send notify to channel about client leaving SILC and thus
the entire channel. */
silc_server_send_notify_to_channel(server, NULL, channel, FALSE,
- SILC_NOTIFY_TYPE_SIGNOFF, 1,
- clidp->data, clidp->len);
+ SILC_NOTIFY_TYPE_SIGNOFF,
+ signoff_message ? 2 : 1,
+ clidp->data, clidp->len,
+ signoff_message, signoff_message ?
+ strlen(signoff_message) : 0);
}
silc_buffer_free(clidp);
SilcPacketContext *packet);
void silc_server_close_connection(SilcServer server,
SilcSocketConnection sock);
+void silc_server_free_client_data(SilcServer server,
+ SilcSocketConnection sock,
+ SilcClientEntry user_data, char *signoff);
void silc_server_free_sock_user_data(SilcServer server,
SilcSocketConnection sock);
int silc_server_channel_has_global(SilcChannelEntry channel);
SilcServerEntry entry);
void silc_server_remove_from_channels(SilcServer server,
SilcSocketConnection sock,
- SilcClientEntry client);
+ SilcClientEntry client,
+ char *signoff_message);
int silc_server_remove_from_one_channel(SilcServer server,
SilcSocketConnection sock,
SilcChannelEntry channel,
and broadcast it to the network.
Max Arguments: 2
- Arguments: (1) <Client ID> (2) <message>
+ Arguments: (1) <Client ID> (2) <message>
The <Client ID> is the client who left SILC network. The <message>
is free text string indicating the reason of signoff.
return;
}
- client->ops->say(client, conn, "Connection closed: premature EOF");
- SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock));
+ SILC_LOG_DEBUG(("EOF from connection %d", sock->sock));
client->ops->disconnect(client, conn);
silc_client_close_connection(client, sock);
return;
silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
client_entry->id);
+ /* Get signoff message */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (tmp_len > 128)
+ tmp = NULL;
+
/* Notify application */
- client->ops->notify(client, conn, type, client_entry);
+ client->ops->notify(client, conn, type, client_entry, tmp);
/* Free data */
if (client_entry->nickname)
SILC_CLIENT_CMD(list, LIST, "LIST", SILC_CF_LAG | SILC_CF_REG, 2),
SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", SILC_CF_LAG | SILC_CF_REG, 3),
SILC_CLIENT_CMD(invite, INVITE, "INVITE", SILC_CF_LAG | SILC_CF_REG, 3),
- SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 1),
+ SILC_CLIENT_CMD(quit, QUIT, "QUIT", SILC_CF_LAG | SILC_CF_REG, 2),
SILC_CLIENT_CMD(kill, KILL, "KILL",
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
SILC_CLIENT_CMD(info, INFO, "INFO", SILC_CF_LAG | SILC_CF_REG, 2),
silc_client_command_free(cmd);
}
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+} *QuitInternal;
+
+SILC_TASK_CALLBACK(silc_client_command_quit_cb)
+{
+ QuitInternal q = (QuitInternal)context;
+
+ /* Close connection */
+ q->client->ops->disconnect(q->client, q->conn);
+ silc_client_close_connection(q->client, q->conn->sock);
+
+ silc_free(q);
+}
+
/* Command QUIT. Closes connection with current server. */
SILC_CLIENT_CMD_FUNC(quit)
{
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcBuffer buffer;
+ QuitInternal q;
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
goto out;
}
- buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
- ++cmd->argv, ++cmd->argv_lens,
- ++cmd->argv_types, 0);
+ if (cmd->argc > 1)
+ buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, cmd->argc - 1,
+ &cmd->argv[1], &cmd->argv_lens[1],
+ &cmd->argv_types[1], 0);
+ else
+ buffer = silc_command_payload_encode(SILC_COMMAND_QUIT, 0,
+ NULL, NULL, NULL, 0);
silc_client_packet_send(cmd->client, cmd->conn->sock, SILC_PACKET_COMMAND,
NULL, 0, NULL, NULL,
buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- cmd->argv--;
- cmd->argv_lens--;
- cmd->argv_types--;
- /* Close connection */
- cmd->client->ops->disconnect(cmd->client, cmd->conn);
- silc_client_close_connection(cmd->client, cmd->conn->sock);
+ q = silc_calloc(1, sizeof(*q));
+ q->client = cmd->client;
+ q->conn = cmd->conn;
+
+ /* We quit the connection with little timeout */
+ silc_task_register(cmd->client->timeout_queue, cmd->conn->sock->sock,
+ silc_client_command_quit_cb, (void *)q,
+ 1, 0, SILC_TASK_TIMEOUT, SILC_TASK_PRI_NORMAL);
/* Notify application */
COMMAND;
/* Verify signature */
silc_pkcs_public_key_data_set(ske->prop->pkcs, public_key->pk,
public_key->pk_len);
- if (ske->prop->pkcs->pkcs->verify(ske->prop->pkcs->context,
- payload->sign_data, payload->sign_len,
- hash, hash_len) == FALSE) {
+ if (silc_pkcs_verify(ske->prop->pkcs, payload->sign_data,
+ payload->sign_len, hash, hash_len) == FALSE) {
SILC_LOG_DEBUG(("Signature don't match"));
/* Sign the hash value */
silc_pkcs_private_key_data_set(ske->prop->pkcs, private_key->prv,
private_key->prv_len);
- ske->prop->pkcs->pkcs->sign(ske->prop->pkcs->context,
- hash, hash_len,
- sign, &sign_len);
+ silc_pkcs_sign(ske->prop->pkcs, hash, hash_len, sign, &sign_len);
ske->ke2_payload->sign_data = silc_calloc(sign_len, sizeof(unsigned char));
memcpy(ske->ke2_payload->sign_data, sign, sign_len);
memset(sign, 0, sizeof(sign));