+Fri Apr 12 10:17:51 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
+
+ * Defined that server receives WHOIS command reply for private
+ and secret channels too. Updated protocol specs and the
+ code in server. Affected file silcd/command.c.
+
+ * Defined <channel user mode list> argument to WHOIS command
+ reply for returning user modes on the channels. The
+ channel list now doesn't include the user mode anymore but the
+ actual channel mode. Updated protocol specs and the code in
+ client and server. Affected files are silcd/command_reply.c,
+ silcd/command.c, silcd/server.c, irssi/src/silc/core/client_ops.c,
+ and lib/silcclient/command_reply.c.
+
+ * Save the channels list in WHOIS command reply in normal server
+ so that WHOIS always shows joined channels also in normal
+ server and not just on router. Affected file is
+ silcd/command_reply.c.
+
Thu Apr 11 22:29:33 EEST 2002 Pekka Riikonen <priikone@silcnet.org>
* Defined that server receives USERS command reply for private
{
SILC_SERVER_REC *server = conn->context;
- if (!server && status == SILC_CLIENT_CONN_ERROR) {
+ if (!server || status == SILC_CLIENT_CONN_ERROR) {
silc_client_close_connection(client, conn);
return;
}
char buf[1024], *nickname, *username, *realname, *nick;
unsigned char *fingerprint;
SilcUInt32 idle, mode;
- SilcBuffer channels;
+ SilcBuffer channels, user_modes;
SilcClientEntry client_entry;
if (status == SILC_STATUS_ERR_NO_SUCH_NICK) {
mode = va_arg(vp, SilcUInt32);
idle = va_arg(vp, SilcUInt32);
fingerprint = va_arg(vp, unsigned char *);
+ user_modes = va_arg(vp, SilcBuffer);
silc_parse_userfqdn(nickname, &nick, NULL);
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_WHOIS_REALNAME, realname);
silc_free(nick);
- if (channels) {
+ if (channels && user_modes) {
+ SilcUInt32 *umodes;
SilcDList list = silc_channel_payload_parse_list(channels->data,
channels->len);
- if (list) {
+ if (list && silc_get_mode_list(user_modes, silc_dlist_count(list),
+ &umodes)) {
SilcChannelPayload entry;
+ int i = 0;
+
memset(buf, 0, sizeof(buf));
silc_dlist_start(list);
while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
- char *m = silc_client_chumode_char(silc_channel_get_mode(entry));
SilcUInt32 name_len;
+ char *m = silc_client_chumode_char(umodes[i++]);
char *name = silc_channel_get_name(entry, &name_len);
if (m)
printformat_module("fe-common/silc", server, NULL, MSGLEVEL_CRAP,
SILCTXT_WHOIS_CHANNELS, buf);
silc_channel_payload_list_free(list);
+ silc_free(umodes);
}
}
/* Try to read detached session data and use it if found. */
memset(¶ms, 0, sizeof(params));
memset(file, 0, sizeof(file));
- snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir(),
- server->connrec->address, server->connrec->port);
+ snprintf(file, sizeof(file) - 1, "%s/session", get_irssi_dir());
params.detach_data = silc_file_readfile(file, ¶ms.detach_data_len);
/* Add connection to the client library */
if (server->conn && server->conn->sock != NULL) {
silc_client_close_connection(silc_client, server->conn);
-
+
/* SILC closes the handle */
g_io_channel_unref(net_sendbuffer_handle(server->handle));
net_sendbuffer_destroy(server->handle, FALSE);
SilcServer server = cmd->server;
char *tmp;
int i, k, len, valid_count;
- SilcBuffer packet, idp, channels;
+ SilcBuffer packet, idp, channels, umode_list = NULL;
SilcClientEntry entry;
SilcCommandStatus status;
SilcUInt16 ident = silc_command_get_ident(cmd->payload);
strncat(uh, hsock->hostname, len);
}
- channels = silc_server_get_client_channel_list(server, entry);
+ if (cmd->sock->type == SILC_SOCKET_TYPE_CLIENT)
+ channels = silc_server_get_client_channel_list(server, entry, FALSE,
+ FALSE, &umode_list);
+ else
+ channels = silc_server_get_client_channel_list(server, entry, TRUE,
+ TRUE, &umode_list);
if (entry->data.fingerprint[0] != 0 && entry->data.fingerprint[1] != 0)
fingerprint = entry->data.fingerprint;
SILC_PUT32_MSB(entry->mode, mode);
- if (entry->connection)
+ if (entry->connection) {
SILC_PUT32_MSB((time(NULL) - entry->data.last_receive), idle);
+ }
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
- status, 0, ident, 8,
+ status, 0, ident, 9,
2, idp->data, idp->len,
3, nh, strlen(nh),
4, uh, strlen(uh),
7, mode, 4,
8, idle, 4,
9, fingerprint,
- fingerprint ? 20 : 0);
+ fingerprint ? 20 : 0,
+ 10, umode_list ? umode_list->data :
+ NULL, umode_list ? umode_list->len :
+ 0);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
silc_buffer_free(idp);
if (channels)
silc_buffer_free(channels);
+ if (umode_list) {
+ silc_buffer_free(umode_list);
+ umode_list = NULL;
+ }
k++;
}
channel = silc_idlist_find_channel_by_name(server->local_list,
channel_name, NULL);
- if (!channel || channel->disabled) {
+ if (!channel || channel->disabled || !channel->users_resolved) {
if (server->server_type != SILC_ROUTER && !server->standalone &&
!cmd->pending) {
SilcBuffer tmpbuf;
silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
{
SilcServer server = cmd->server;
- unsigned char *tmp, *id_data;
+ unsigned char *tmp, *id_data, *umodes;
char *nickname, *username, *realname, *servername = NULL;
unsigned char *fingerprint;
SilcClientID *client_id;
SilcClientEntry client;
+ SilcIDCacheEntry cache = NULL;
char global = FALSE;
char *nick;
- SilcUInt32 mode = 0, len, id_len, flen;
- int expire = 0;
+ SilcUInt32 mode = 0, len, len2, id_len, flen;
id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
- /* If client is global and is not on any channel then add that we'll
- expire the entry after a while. */
- if (global && !silc_hash_table_count(client->channels) &&
- server->server_type == SILC_SERVER)
- expire = time(NULL) + 300;
-
/* Create new cache entry */
silc_idcache_add(global ? server->global_list->clients :
server->local_list->clients, nick, client->id,
- client, expire, NULL);
+ client, 0, &cache);
silc_free(client_id);
}
+ /* Save channel list if it was sent to us */
+ if (server->server_type == SILC_SERVER) {
+ tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
+ umodes = silc_argument_get_arg_type(cmd->args, 10, &len2);
+ if (tmp && umodes) {
+ SilcBufferStruct channels_buf, umodes_buf;
+ silc_buffer_set(&channels_buf, tmp, len);
+ silc_buffer_set(&umodes_buf, umodes, len2);
+ silc_server_save_user_channels(server, cmd->sock, client, &channels_buf,
+ &umodes_buf);
+ } else {
+ silc_server_save_user_channels(server, cmd->sock, client, NULL, NULL);
+ }
+
+ if (cache)
+ /* If client is global and is not on any channel then add that we'll
+ expire the entry after a while. */
+ if (global && !silc_hash_table_count(client->channels))
+ cache->expire = time(NULL) + 300;
+ }
+
if (fingerprint && flen == sizeof(client->data.fingerprint))
memcpy(client->data.fingerprint, fingerprint, flen);
silc_server_save_users_on_channel(server, cmd->sock, entry,
client_id, client_id_list,
client_mode_list, list_count);
+ entry->users_resolved = TRUE;
out:
SILC_SERVER_PENDING_EXEC(cmd, SILC_COMMAND_JOIN);
client_id_list, client_mode_list,
list_count);
+ channel->global_users = silc_server_channel_has_global(channel);
+ channel->users_resolved = TRUE;
+
silc_buffer_free(client_id_list);
silc_buffer_free(client_mode_list);
unsigned long created;
bool disabled;
+ bool users_resolved;
};
/*
silc_id_render(channel_id, SILC_ID_CHANNEL),
sock->hostname));
- silc_idlist_add_channel(server->global_list, strdup(channel_name),
- 0, channel_id, sock->user_data, NULL, NULL, 0);
+ channel =
+ silc_idlist_add_channel(server->global_list, strdup(channel_name),
+ 0, channel_id, sock->user_data, NULL, NULL, 0);
+ if (!channel)
+ return;
+
server->stat.channels++;
+ if (server->server_type == SILC_ROUTER)
+ channel->users_resolved = TRUE;
}
} else {
/* The channel is coming from our server, thus it is in our cell
return;
}
- /* Check that the client is detached */
- if (!(detached_client->mode & SILC_UMODE_DETACHED)) {
+ /* Check that the client is detached, and that we have other info too */
+ if (!(detached_client->mode & SILC_UMODE_DETACHED) ||
+ !silc_hash_table_count(detached_client->channels) ||
+ !detached_client->nickname) {
if (server->server_type == SILC_SERVER && !server->standalone) {
/* The client info is being resolved. Reprocess this packet after
receiving the reply to the query. */
- SILC_LOG_DEBUG(("Resolving client mode"));
+ SILC_LOG_DEBUG(("Resolving client info"));
silc_server_get_client_resolve(server, client_id, TRUE, NULL);
r = silc_calloc(1, sizeof(*r));
if (!r)
client->nickname);
}
+ /* Resolve users on those channels that client has joined but we
+ haven't resolved user list yet. */
+ if (server->server_type == SILC_SERVER && !server->standalone) {
+ silc_hash_table_list(client->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+ channel = chl->channel;
+ SILC_LOG_DEBUG(("Resolving users for %s channel",
+ channel->channel_name));
+ if (channel->disabled || !channel->users_resolved) {
+ silc_server_send_command(server, server->router->connection,
+ SILC_COMMAND_USERS, ++server->cmd_ident,
+ 1, 2, channel->channel_name,
+ strlen(channel->channel_name));
+ }
+ }
+ silc_hash_table_list_reset(&htl);
+ }
+
/* Send the new client ID to the client. After this client may start
receiving other packets, and may start sending packets too. */
silc_server_send_new_id(server, sock, FALSE, client_id, SILC_ID_CLIENT,
/* Send some nice info to the client */
silc_server_send_connect_notifys(server, sock, client);
- /* XXX normal server may not know about any joined channels!!!
- Do this by saving the joined list in the resume_resolve callback.
- Resolve it here with USERS per channel. */
-
-
/* Send all channel keys of channels the client has joined */
silc_hash_table_list(client->channels, &htl);
while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+ bool created = FALSE;
channel = chl->channel;
+
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY)
+ continue;
+
+ /* If we don't have channel key, then create one */
+ if (!channel->channel_key) {
+ if (!silc_server_create_channel_key(server, channel, 0))
+ continue;
+ created = TRUE;
+ }
+
id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
keyp =
silc_channel_key_payload_encode(silc_id_get_len(channel->id,
/* Send the key packet to client */
silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
keyp->data, keyp->len, FALSE);
- channel->global_users = silc_server_channel_has_global(channel);
+
+ if (created && server->server_type == SILC_SERVER &&
+ !server->standalone)
+ silc_server_packet_send(server, server->router->connection,
+ SILC_PACKET_CHANNEL_KEY, 0,
+ keyp->data, keyp->len, FALSE);
+
+ silc_buffer_free(keyp);
}
silc_hash_table_list_reset(&htl);
server->stat.my_channels++;
+ if (server->server_type == SILC_ROUTER)
+ entry->users_resolved = TRUE;
+
return entry;
}
server->stat.my_channels++;
+ if (server->server_type == SILC_ROUTER)
+ entry->users_resolved = TRUE;
+
return entry;
}
}
}
+/* Saves channels and channels user modes to the `client'. Removes
+ the client from those channels that are not sent in the list but
+ it has joined. */
+
+void silc_server_save_user_channels(SilcServer server,
+ SilcSocketConnection sock,
+ SilcClientEntry client,
+ SilcBuffer channels,
+ SilcBuffer channels_user_modes)
+{
+ SilcDList ch;
+ SilcUInt32 *chumodes;
+ SilcChannelPayload entry;
+ SilcChannelEntry channel;
+ SilcChannelID *channel_id;
+ SilcChannelClientEntry chl;
+ SilcHashTable ht = NULL;
+ SilcHashTableList htl;
+ char *name;
+ int i = 0;
+
+ if (!channels ||!channels_user_modes)
+ goto out;
+
+ ch = silc_channel_payload_parse_list(channels->data, channels->len);
+ if (ch && silc_get_mode_list(channels_user_modes, silc_dlist_count(ch),
+ &chumodes)) {
+ ht = silc_hash_table_alloc(0, silc_hash_ptr, NULL, NULL,
+ NULL, NULL, NULL, TRUE);
+ silc_dlist_start(ch);
+ while ((entry = silc_dlist_get(ch)) != SILC_LIST_END) {
+ /* Check if we have this channel, and add it if we don't have it.
+ Also add the client on the channel unless it is there already. */
+ channel_id = silc_channel_get_id_parse(entry);
+ channel = silc_idlist_find_channel_by_id(server->local_list,
+ channel_id, NULL);
+ if (!channel)
+ channel = silc_idlist_find_channel_by_id(server->global_list,
+ channel_id, NULL);
+ if (!channel) {
+ if (server->server_type != SILC_SERVER) {
+ silc_free(channel_id);
+ i++;
+ continue;
+ }
+
+ /* We don't have that channel anywhere, add it. */
+ name = silc_channel_get_name(entry, NULL);
+ channel = silc_idlist_add_channel(server->global_list, strdup(name), 0,
+ channel_id, server->router,
+ NULL, NULL, 0);
+ if (!channel) {
+ silc_free(channel_id);
+ i++;
+ continue;
+ }
+ channel_id = NULL;
+ }
+
+ channel->mode = silc_channel_get_mode(entry);
+
+ /* Add the client on the channel */
+ if (!silc_server_client_on_channel(client, channel, &chl)) {
+ chl = silc_calloc(1, sizeof(*chl));
+ chl->client = client;
+ chl->mode = chumodes[i++];
+ chl->channel = channel;
+ silc_hash_table_add(channel->user_list, chl->client, chl);
+ silc_hash_table_add(client->channels, chl->channel, chl);
+ channel->user_count++;
+ } else {
+ /* Update mode */
+ chl->mode = chumodes[i++];
+ }
+
+ silc_hash_table_add(ht, channel, channel);
+ silc_free(channel_id);
+ }
+ silc_channel_payload_list_free(ch);
+ silc_free(chumodes);
+ }
+
+ out:
+ /* Go through the list again and remove client from channels that
+ are no part of the list. */
+ if (ht) {
+ silc_hash_table_list(client->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+ if (!silc_hash_table_find(ht, chl->channel, NULL, NULL)) {
+ silc_hash_table_del(chl->channel->user_list, chl->client);
+ silc_hash_table_del(chl->client->channels, chl->channel);
+ silc_free(chl);
+ }
+ }
+ silc_hash_table_list_reset(&htl);
+ silc_hash_table_free(ht);
+ } else {
+ silc_hash_table_list(client->channels, &htl);
+ while (silc_hash_table_get(&htl, NULL, (void **)&chl)) {
+ silc_hash_table_del(chl->channel->user_list, chl->client);
+ silc_hash_table_del(chl->client->channels, chl->channel);
+ silc_free(chl);
+ }
+ silc_hash_table_list_reset(&htl);
+ }
+}
+
/* Lookups route to the client indicated by the `id_data'. The connection
object and internal data object is returned. Returns NULL if route
could not be found to the client. If the `client_id' is specified then
Secret channels are not put to the list. */
SilcBuffer silc_server_get_client_channel_list(SilcServer server,
- SilcClientEntry client)
+ SilcClientEntry client,
+ bool get_private,
+ bool get_secret,
+ SilcBuffer *user_mode_list)
{
SilcBuffer buffer = NULL;
SilcChannelEntry channel;
SilcUInt16 name_len;
int len;
+ if (user_mode_list)
+ *user_mode_list = NULL;
+
silc_hash_table_list(client->channels, &htl);
while (silc_hash_table_get(&htl, NULL, (void *)&chl)) {
channel = chl->channel;
- if (channel->mode & SILC_CHANNEL_MODE_SECRET ||
- channel->mode & SILC_CHANNEL_MODE_PRIVATE)
+ if (channel->mode & SILC_CHANNEL_MODE_SECRET && !get_secret)
+ continue;
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVATE && !get_private)
continue;
cid = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
len = 4 + name_len + id_len + 4;
buffer = silc_buffer_realloc(buffer,
- (buffer ? (buffer)->truelen + len : len));
- silc_buffer_pull_tail(buffer, ((buffer)->end - (buffer)->data));
+ (buffer ? buffer->truelen + len : len));
+ silc_buffer_pull_tail(buffer, (buffer->end - buffer->data));
silc_buffer_format(buffer,
SILC_STR_UI_SHORT(name_len),
SILC_STR_UI_XNSTRING(channel->channel_name,
name_len),
SILC_STR_UI_SHORT(id_len),
SILC_STR_UI_XNSTRING(cid, id_len),
- SILC_STR_UI_INT(chl->mode), /* Client's mode */
+ SILC_STR_UI_INT(chl->channel->mode),
SILC_STR_END);
silc_buffer_pull(buffer, len);
silc_free(cid);
+
+ if (user_mode_list) {
+ *user_mode_list = silc_buffer_realloc(*user_mode_list,
+ (*user_mode_list ?
+ (*user_mode_list)->truelen + 4 :
+ 4));
+ silc_buffer_pull_tail(*user_mode_list, ((*user_mode_list)->end -
+ (*user_mode_list)->data));
+ SILC_PUT32_MSB(chl->mode, (*user_mode_list)->data);
+ silc_buffer_pull(*user_mode_list, 4);
+ }
}
silc_hash_table_list_reset(&htl);
if (buffer)
silc_buffer_push(buffer, buffer->data - buffer->head);
+ if (user_mode_list && *user_mode_list)
+ silc_buffer_push(*user_mode_list, ((*user_mode_list)->data -
+ (*user_mode_list)->head));
return buffer;
}
always_resolve) {
SilcBuffer buffer, idp;
- client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
- client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
- client->resolve_cmd_ident = ++server->cmd_ident;
+ if (client) {
+ client->data.status |= SILC_IDLIST_STATUS_RESOLVING;
+ client->data.status &= ~SILC_IDLIST_STATUS_RESOLVED;
+ client->resolve_cmd_ident = ++server->cmd_ident;
+ }
idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
buffer = silc_command_payload_encode_va(SILC_COMMAND_WHOIS,
SilcBuffer user_list,
SilcBuffer mode_list,
SilcUInt32 user_count);
+void silc_server_save_user_channels(SilcServer server,
+ SilcSocketConnection sock,
+ SilcClientEntry client,
+ SilcBuffer channels,
+ SilcBuffer channels_user_modes);
SilcSocketConnection
silc_server_get_client_route(SilcServer server,
unsigned char *id_data,
SilcIDListData *idata,
SilcClientEntry *client_entry);
SilcBuffer silc_server_get_client_channel_list(SilcServer server,
- SilcClientEntry client);
+ SilcClientEntry client,
+ bool get_private,
+ bool get_secret,
+ SilcBuffer *user_mode_list);
SilcClientEntry silc_server_get_client_resolve(SilcServer server,
SilcClientID *client_id,
bool always_resolve,
Reply messages to the command:
- Max Arguments: 9
+ Max Arguments: 10
Arguments: (1) <Status Payload> (2) <Client ID>
(3) <nickname>[@<server>] (4) <username@host>
(5) <real name> (6) [<Channel Payload
list>]
(7) [<user mode>] (8) [<idle time>]
- (9) [<fingerprint>]
+ (9) [<fingerprint>] (10) <channel user
+ mode list>
This command may reply with several command reply messages to
<count> option were defined in the query there will be only
<count> many replies from the server.
- The server may return the list of channels if the client has
+ The server returns the list of channels if the client has
joined channels. In this case the list is list of Channel
- Payloads. The Mode Mask in the Channel Payload (see [SILC2] and
- section 2.3.2.3 for the Channel Payload) is the client's mode
- on the channel. The list is encoded by adding the Channel
- Payloads one after the other.
-
- The server may also send client's user mode, idle time, and the
+ Payloads. The Mode Mask in the Channel Payload is the channel's
+ mode. The list is encoded by adding the Channel Payloads one
+ after the other. Private and secret channels MUST NOT be sent,
+ except if the sender of this command is on those channels, or
+ the sender is server. The <channel user mode list> MUST also
+ be sent if client is joined channels. This list includes 32 bit
+ MSB first order values one after the other and each indicate
+ the user's mode on a channel. The order of these values MUST
+ be same as the channel order in the <Channel Payload list>.
+
+ The server also returns client's user mode, idle time, and the
fingerprint of the client's public key. The <fingerprint> is the
binary hash digest of the public key. The fingerprint MUST NOT
be sent if the server has not verified the proof of posession of
SILC_CLIENT_CONN_SUCCESS_RESUME :
SILC_CLIENT_CONN_ERROR);
- /* Issue INFO command to fetch the real server name and server
- information and other stuff. */
- silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
- silc_client_command_reply_info_i, 0,
- ++conn->cmd_ident);
- sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
- silc_client_command_send(client, conn, SILC_COMMAND_INFO,
- conn->cmd_ident, 1, 2, sidp->data, sidp->len);
- silc_buffer_free(sidp);
+ if (success) {
+ /* Issue INFO command to fetch the real server name and server
+ information and other stuff. */
+ silc_client_command_register(client, SILC_COMMAND_INFO, NULL, NULL,
+ silc_client_command_reply_info_i, 0,
+ ++conn->cmd_ident);
+ sidp = silc_id_payload_encode(conn->remote_id, SILC_ID_SERVER);
+ silc_client_command_send(client, conn, SILC_COMMAND_INFO,
+ conn->cmd_ident, 1, 2, sidp->data, sidp->len);
+ silc_buffer_free(sidp);
+ }
}
/* Processes the received new Client ID from server. Old Client ID is
tmp = silc_argument_get_arg_type(args, 3, NULL);
if (tmp) {
/* Protocol version 1.1 */
- char *tmp_nick;
+ char *tmp_nick = NULL;
/* Check whether nickname changed at all. It is possible that nick
change notify is received but nickname didn't changed, only the
else
tmp_nick = strdup(tmp);
- if (!strcmp(tmp, tmp_nick)) {
+ if (tmp_nick && !strcmp(tmp, tmp_nick)) {
/* Nickname didn't change. Update only the ID */
silc_idcache_del_by_context(conn->client_cache, client_entry);
silc_free(client_entry->id);
SILC_CLIENT_CMD_FUNC(resume_cmode);
SILC_CLIENT_CMD_FUNC(resume_users);
+#define RESUME_CALL_COMPLETION(client, session, s) \
+do { \
+ session->success = s; \
+ silc_schedule_task_add(client->schedule, 0, \
+ silc_client_resume_call_completion, session, \
+ 0, 1, SILC_TASK_TIMEOUT, SILC_TASK_PRI_LOW); \
+} while(0)
+
/* Generates the session detachment data. This data can be used later
to resume back to the server. */
return TRUE;
}
+
+/* Resume session context */
+typedef struct {
+ SilcClient client;
+ SilcClientConnection conn;
+ SilcClientResumeSessionCallback callback;
+ void *context;
+ SilcUInt32 channel_count;
+ bool success;
+} *SilcClientResumeSession;
+
/* Generic command reply callback */
SILC_CLIENT_CMD_REPLY_FUNC(resume)
(*cmd->callback)(cmd->context, cmd);
}
-/* Resume session context */
-typedef struct {
- SilcClient client;
- SilcClientConnection conn;
- SilcClientResumeSessionCallback callback;
- void *context;
- SilcUInt32 channel_count;
-} *SilcClientResumeSession;
+/* Completion calling callback */
+
+SILC_TASK_CALLBACK(silc_client_resume_call_completion)
+{
+ SilcClientResumeSession session = context;
+ session->callback(session->client, session->conn, session->success,
+ session->context);
+}
/* This function is used to perform the resuming procedure after the
client has connected to the server properly and has received the
err:
session->channel_count--;
if (!session->channel_count)
- session->callback(session->client, session->conn, FALSE,
- session->context);
+ RESUME_CALL_COMPLETION(client, session, FALSE);
}
/* Received cmode to channel entry */
err:
session->channel_count--;
if (!session->channel_count)
- session->callback(session->client, session->conn, FALSE,
- session->context);
+ RESUME_CALL_COMPLETION(client, session, FALSE);
}
/* Received users reply to a channel entry */
our channels */
session->channel_count--;
if (!session->channel_count)
- session->callback(session->client, session->conn, TRUE,
- session->context);
+ RESUME_CALL_COMPLETION(client, session, TRUE);
silc_free(channel_id);
return;
silc_free(channel_id);
session->channel_count--;
if (!session->channel_count)
- session->callback(session->client, session->conn, FALSE,
- session->context);
+ RESUME_CALL_COMPLETION(client, session, FALSE);
}
char *nickname = NULL, *username = NULL;
char *realname = NULL;
SilcUInt32 idle = 0, mode = 0;
- SilcBufferStruct channels;
+ SilcBufferStruct channels, ch_user_modes;
+ bool has_channels = FALSE, has_user_modes = FALSE;
unsigned char *fingerprint;
SilcUInt32 fingerprint_len;
}
tmp = silc_argument_get_arg_type(cmd->args, 6, &len);
- if (tmp)
+ if (tmp) {
silc_buffer_set(&channels, tmp, len);
+ has_channels = TRUE;
+ }
tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
if (tmp)
fingerprint = silc_argument_get_arg_type(cmd->args, 9, &fingerprint_len);
+ tmp = silc_argument_get_arg_type(cmd->args, 10, &len);
+ if (tmp) {
+ silc_buffer_set(&ch_user_modes, tmp, len);
+ has_user_modes = TRUE;
+ }
+
/* Check if we have this client cached already. */
client_entry = silc_client_get_client_by_id(cmd->client, conn, client_id);
if (!client_entry) {
/* Notify application */
if (!cmd->callback && notify)
COMMAND_REPLY((ARGS, client_entry, nickname, username, realname,
- &channels, mode, idle, fingerprint));
+ has_channels ? &channels : NULL, mode, idle,
+ fingerprint, has_user_modes ? &ch_user_modes : NULL));
}
/* Received reply for WHOIS command. This maybe called several times
return NULL;
#endif /* SILC_UNIX */
}
+
+/* Return mode list */
+
+bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
+ SilcUInt32 **list)
+{
+ int i;
+
+ if (mode_list->len / 4 != mode_list_count)
+ return FALSE;
+
+ *list = silc_calloc(mode_list_count, sizeof(**list));
+
+ for (i = 0; i < mode_list_count; i++) {
+ SILC_GET32_MSB((*list)[i], mode_list->data);
+ silc_buffer_pull(mode_list, 4);
+ }
+
+ silc_buffer_push(mode_list, mode_list->data - mode_list->head);
+
+ return TRUE;
+}
***/
char *silc_get_real_name();
+/****f* silcutil/SilcUtilAPI/silc_get_mode_list
+ *
+ * SYNOPSIS
+ *
+ * bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
+ * SilcUInt32 **list);
+ *
+ * DESCRIPTION
+ *
+ * Returns modes from list of 32 bit MSB first order values that are
+ * encoded one after the other in the `mode_list' into the `list'
+ * array. The caller must free the returned list. Return FALSE if
+ * there is error parsing the list.
+ *
+ ***/
+bool silc_get_mode_list(SilcBuffer mode_list, SilcUInt32 mode_list_count,
+ SilcUInt32 **list);
+
#endif /* !SILCUTIL_H */