From bb7b74bba3baa4ab2777536b2f3424efd09d9c4f Mon Sep 17 00:00:00 2001 From: Pekka Riikonen Date: Sun, 10 Jun 2007 18:32:58 +0000 Subject: [PATCH] Added support for channel@server channel name strings (SILC protocol 1.3 change). Added full_nicknames and full_channel_name SilcClientParams. --- CHANGES | 12 ++++ lib/silcclient/client_entry.c | 107 +++++++++++++++++++++++------- lib/silcclient/command.c | 48 +++++++++++--- lib/silcclient/command_reply.c | 8 ++- lib/silcclient/silcclient.h | 22 +++++- lib/silcclient/silcclient_entry.h | 3 +- 6 files changed, 162 insertions(+), 38 deletions(-) diff --git a/CHANGES b/CHANGES index ac255b55..87a83573 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ +Sun Jun 10 17:32:15 EEST 2007 Pekka Riikonen + + * Added support for channel@server channel name strings to + client library (SILC protocol version 1.3 change). Affected + files are lib/silcclient/silcclient_entry.h, client_entry.c. + + * Added full_nicknames and full_channel_names settings to + SilcClientParams that can be used to specify whether client + library returns full nickname and channel name strings. + Full strings are nick@server and channel@server. Affected + file is lib/silcclient/client_entry.c and command.c. + Sat Jun 9 19:43:25 EEST 2007 Pekka Riikonen * Fixed unix connecting failure to return error code correctly. diff --git a/lib/silcclient/client_entry.c b/lib/silcclient/client_entry.c index 6a92210a..0c812de0 100644 --- a/lib/silcclient/client_entry.c +++ b/lib/silcclient/client_entry.c @@ -781,7 +781,7 @@ SilcClientEntry silc_client_add_client(SilcClient client, SilcUInt32 mode) { SilcClientEntry client_entry; - char *nick = NULL; + char *nick = NULL, parsed[128 + 1]; SILC_LOG_DEBUG(("Adding new client entry")); @@ -795,14 +795,21 @@ SilcClientEntry silc_client_add_client(SilcClient client, client_entry->id = *id; client_entry->mode = mode; client_entry->realname = userinfo ? strdup(userinfo) : NULL; - silc_parse_userfqdn(nickname, client_entry->nickname, - sizeof(client_entry->nickname), - client_entry->server, - sizeof(client_entry->server)); + + silc_parse_userfqdn(nickname, parsed, sizeof(parsed), + client_entry->server, sizeof(client_entry->server)); + if (nickname && client->internal->params->full_nicknames) + silc_snprintf(client_entry->nickname, sizeof(client_entry->nickname), + nickname); + else if (nickname) + silc_snprintf(client_entry->nickname, sizeof(client_entry->nickname), + parsed); + silc_parse_userfqdn(username, client_entry->username, sizeof(client_entry->username), client_entry->hostname, sizeof(client_entry->hostname)); + client_entry->channels = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL, NULL, NULL, NULL, TRUE); if (!client_entry->channels) { @@ -813,8 +820,7 @@ SilcClientEntry silc_client_add_client(SilcClient client, /* Normalize nickname */ if (client_entry->nickname[0]) { - nick = silc_identifier_check(client_entry->nickname, - strlen(client_entry->nickname), + nick = silc_identifier_check(parsed, strlen(parsed), SILC_STRING_UTF8, 128, NULL); if (!nick) { silc_free(client_entry->realname); @@ -864,7 +870,7 @@ void silc_client_update_client(SilcClient client, const char *userinfo, SilcUInt32 mode) { - char *nick = NULL; + char *nick = NULL, parsed[128 + 1]; SILC_LOG_DEBUG(("Update client entry")); @@ -872,20 +878,25 @@ void silc_client_update_client(SilcClient client, if (!client_entry->realname && userinfo) client_entry->realname = strdup(userinfo); + if ((!client_entry->username[0] || !client_entry->hostname[0]) && username) silc_parse_userfqdn(username, client_entry->username, sizeof(client_entry->username), client_entry->hostname, sizeof(client_entry->username)); + if (!client_entry->nickname[0] && nickname) { - silc_parse_userfqdn(nickname, client_entry->nickname, - sizeof(client_entry->nickname), - client_entry->server, - sizeof(client_entry->server)); + silc_parse_userfqdn(nickname, parsed, sizeof(parsed), + client_entry->server, sizeof(client_entry->server)); + if (client->internal->params->full_nicknames) + silc_snprintf(client_entry->nickname, sizeof(client_entry->nickname), + nickname); + else + silc_snprintf(client_entry->nickname, sizeof(client_entry->nickname), + parsed); /* Normalize nickname */ - nick = silc_identifier_check(client_entry->nickname, - strlen(client_entry->nickname), + nick = silc_identifier_check(parsed, strlen(parsed), SILC_STRING_UTF8, 128, NULL); if (!nick) { silc_rwlock_unlock(client_entry->internal.lock); @@ -1357,32 +1368,66 @@ SilcChannelEntry silc_client_get_channel(SilcClient client, SilcClientConnection conn, char *channel) { + SilcList list; SilcIDCacheEntry id_cache; - SilcChannelEntry entry; + SilcChannelEntry entry = NULL; + char chname[256 + 1], server[256 + 1]; if (!client || !conn || !channel) return NULL; SILC_LOG_DEBUG(("Find channel %s", channel)); + /* Parse server name from channel name */ + silc_parse_userfqdn(channel, chname, sizeof(chname), server, sizeof(server)); + /* Normalize name for search */ - channel = silc_channel_name_check(channel, strlen(channel), SILC_STRING_UTF8, + channel = silc_channel_name_check(chname, strlen(chname), SILC_STRING_UTF8, 256, NULL); if (!channel) return NULL; silc_mutex_lock(conn->internal->lock); - if (!silc_idcache_find_by_name_one(conn->internal->channel_cache, channel, - &id_cache)) { + if (!silc_idcache_find_by_name(conn->internal->channel_cache, channel, + &list)) { silc_mutex_unlock(conn->internal->lock); silc_free(channel); return NULL; } - SILC_LOG_DEBUG(("Found")); + /* If server name was specified with channel name, find the correct + channel entry with the server name. There can only be one channel + with same name on same server. */ + silc_list_start(list); + if (server[0]) { + while ((id_cache = silc_list_get(list))) { + entry = id_cache->context; + if (!entry->server[0]) + continue; + if (silc_utf8_strcasecmp(entry->server, server)) + break; + } + } else { + /* Get first channel without server name specified or one with our + current server connection name */ + while ((id_cache = silc_list_get(list))) { + entry = id_cache->context; + if (!entry->server[0]) + break; + if (silc_utf8_strcasecmp(entry->server, conn->remote_host)) + break; + } + } - entry = id_cache->context; + if (!id_cache) { + silc_mutex_unlock(conn->internal->lock); + silc_free(channel); + return NULL; + } + + SILC_LOG_DEBUG(("Found channel %s%s%s", entry->channel_name, + entry->server[0] ? "@" : "", entry->server)); /* Reference */ silc_client_ref_channel(client, conn, entry); @@ -1571,9 +1616,9 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, SilcChannelID *channel_id) { SilcChannelEntry channel; - char *channel_namec; + char *channel_namec, name[256 + 1]; - SILC_LOG_DEBUG(("Start")); + SILC_LOG_DEBUG(("Adding channel %s", channel_name)); channel = silc_calloc(1, sizeof(*channel)); if (!channel) @@ -1584,8 +1629,16 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, channel->id = *channel_id; channel->mode = mode; - channel->channel_name = strdup(channel_name); + silc_parse_userfqdn(channel_name, name, sizeof(name), + channel->server, sizeof(channel->server)); + if (client->internal->params->full_channel_names) + channel->channel_name = strdup(channel_name); + else + channel->channel_name = strdup(name); + if (!channel->channel_name) { + silc_rwlock_free(channel->internal.lock); + silc_atomic_uninit16(&channel->internal.refcnt); silc_free(channel); return NULL; } @@ -1593,15 +1646,19 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, channel->user_list = silc_hash_table_alloc(1, silc_hash_ptr, NULL, NULL, NULL, NULL, NULL, TRUE); if (!channel->user_list) { + silc_rwlock_free(channel->internal.lock); + silc_atomic_uninit16(&channel->internal.refcnt); silc_free(channel->channel_name); silc_free(channel); return NULL; } /* Normalize channel name */ - channel_namec = silc_channel_name_check(channel_name, strlen(channel_name), + channel_namec = silc_channel_name_check(name, strlen(name), SILC_STRING_UTF8, 256, NULL); if (!channel_namec) { + silc_rwlock_free(channel->internal.lock); + silc_atomic_uninit16(&channel->internal.refcnt); silc_free(channel->channel_name); silc_hash_table_free(channel->user_list); silc_free(channel); @@ -1613,6 +1670,8 @@ SilcChannelEntry silc_client_add_channel(SilcClient client, /* Add channel to cache, the normalized channel name is saved to cache */ if (!silc_idcache_add(conn->internal->channel_cache, channel_namec, &channel->id, channel)) { + silc_rwlock_free(channel->internal.lock); + silc_atomic_uninit16(&channel->internal.refcnt); silc_free(channel_namec); silc_free(channel->channel_name); silc_hash_table_free(channel->user_list); diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index 0f66b97a..85e33fe3 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -938,7 +938,7 @@ SILC_FSM_STATE(silc_client_command_topic) SilcClient client = conn->client; SilcChannelEntry channel; SilcBuffer idp; - char *name; + char *name, tmp[512]; if (cmd->argc < 2 || cmd->argc > 3) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, @@ -953,7 +953,15 @@ SILC_FSM_STATE(silc_client_command_topic) COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - name = conn->current_channel->channel_name; + + if (client->internal->params->full_channel_names) + silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name); + else + silc_snprintf(tmp, sizeof(tmp), "%s%s%s", + conn->current_channel->channel_name, + conn->current_channel->server[0] ? "@" : "", + conn->current_channel->server); + name = tmp; } else { name = cmd->argv[1]; } @@ -2119,7 +2127,7 @@ SILC_FSM_STATE(silc_client_command_kick) SilcBuffer idp, idp2; SilcClientEntry target; SilcDList clients = NULL; - char *name; + char *name, tmp[512]; if (cmd->argc < 3) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, @@ -2133,7 +2141,15 @@ SILC_FSM_STATE(silc_client_command_kick) COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - name = conn->current_channel->channel_name; + + if (client->internal->params->full_channel_names) + silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name); + else + silc_snprintf(tmp, sizeof(tmp), "%s%s%s", + conn->current_channel->channel_name, + conn->current_channel->server[0] ? "@" : "", + conn->current_channel->server); + name = tmp; } else { name = cmd->argv[1]; } @@ -2521,7 +2537,7 @@ SILC_FSM_STATE(silc_client_command_leave) SilcClient client = conn->client; SilcChannelEntry channel; SilcBuffer idp; - char *name; + char *name, tmp[512]; if (cmd->argc != 2) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, @@ -2535,7 +2551,15 @@ SILC_FSM_STATE(silc_client_command_leave) COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - name = conn->current_channel->channel_name; + + if (client->internal->params->full_channel_names) + silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name); + else + silc_snprintf(tmp, sizeof(tmp), "%s%s%s", + conn->current_channel->channel_name, + conn->current_channel->server[0] ? "@" : "", + conn->current_channel->server); + name = tmp; } else { name = cmd->argv[1]; } @@ -2580,7 +2604,7 @@ SILC_FSM_STATE(silc_client_command_users) { SilcClientCommandContext cmd = fsm_context; SilcClientConnection conn = cmd->conn; - char *name; + char *name, tmp[512]; if (cmd->argc != 2) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, @@ -2594,7 +2618,15 @@ SILC_FSM_STATE(silc_client_command_users) COMMAND_ERROR(SILC_STATUS_ERR_NOT_ON_CHANNEL); goto out; } - name = conn->current_channel->channel_name; + + if (conn->client->internal->params->full_channel_names) + silc_snprintf(tmp, sizeof(tmp), conn->current_channel->channel_name); + else + silc_snprintf(tmp, sizeof(tmp), "%s%s%s", + conn->current_channel->channel_name, + conn->current_channel->server[0] ? "@" : "", + conn->current_channel->server); + name = tmp; } else { name = cmd->argv[1]; } diff --git a/lib/silcclient/command_reply.c b/lib/silcclient/command_reply.c index 4cb7db06..3c0f56a8 100644 --- a/lib/silcclient/command_reply.c +++ b/lib/silcclient/command_reply.c @@ -677,7 +677,8 @@ SILC_FSM_STATE(silc_client_command_reply_identify) } /* Notify application */ - silc_client_command_callback(cmd, channel_entry, name, info); + silc_client_command_callback(cmd, channel_entry, + channel_entry->channel_name, info); silc_client_unref_channel(client, conn, channel_entry); break; } @@ -800,7 +801,8 @@ SILC_FSM_STATE(silc_client_command_reply_list) } /* Notify application */ - silc_client_command_callback(cmd, channel_entry, name, topic, usercount); + silc_client_command_callback(cmd, channel_entry, channel_entry->channel_name, + topic, usercount); out: silc_client_unref_channel(client, conn, channel_entry); @@ -1302,7 +1304,7 @@ SILC_FSM_STATE(silc_client_command_reply_join) silc_hash_table_list(channel->user_list, &htl); /* Notify application */ - silc_client_command_callback(cmd, channel_name, channel, mode, &htl, + silc_client_command_callback(cmd, channel->channel_name, channel, mode, &htl, topic, cipher, hmac, channel->founder_key, channel->channel_pubkeys, channel->user_limit); diff --git a/lib/silcclient/silcclient.h b/lib/silcclient/silcclient.h index 569b2ab2..898204a1 100644 --- a/lib/silcclient/silcclient.h +++ b/lib/silcclient/silcclient.h @@ -665,13 +665,16 @@ typedef struct SilcClientParamsStruct { %H full hostname - the full hostname of the client Example format strings: "%n#%a" (fe. nick#2, nick#3) - "%n@%h%a" (fe. nick@host, nick@host2) - "%a!%n@%h" (fe. nick@host, 2!nick@host) + "%n#%h%a" (fe. nick#host, nick#host2) + "%a!%n#%h" (fe. nick#host, 2!nick#host) Note that there must always be some separator characters around '%n' format. It is not possible to put format characters before or after '%n' without separators (such ash '#'). Also note that the separator character should be a character that cannot be part of normal nickname. + Note that, using '@' as a separator is not recommended as the nickname + string may contain it to separate a server name from the nickname (eg. + nickname@silcnet.org). */ char nickname_format[32]; @@ -683,6 +686,21 @@ typedef struct SilcClientParamsStruct { value. */ SilcBool nickname_force_format; + /* If this is set to TRUE then all nickname strings returned by the library + and stored by the library are in the format of 'nickname@server', eg. + nickname@silcnet.org. If this is FALSE then the server name of the + nickname is available only from the SilcClientEntry structure. When this + is TRUE the server name is still parsed to SilcClientEntry. */ + SilcBool full_nicknames; + + /* If this is set to TRUE then all channel name strings returned by the + library and stored by the library are in the format of 'channel@server', + eg. silc@silcnet.org. If this is FALSE then the server name of the + channel is available only from the SilcChannelEntry structure. When this + is TRUE the server name is still parsed to SilcChannelEntry. Note that, + not all SILC server versions return such channel name strings. */ + SilcBool full_channel_names; + /* If this is set to TRUE, the silcclient library will not register and deregister the cipher, pkcs, hash and hmac algorithms. The application itself will need to handle that. */ diff --git a/lib/silcclient/silcclient_entry.h b/lib/silcclient/silcclient_entry.h index 7685978e..4b57f859 100644 --- a/lib/silcclient/silcclient_entry.h +++ b/lib/silcclient/silcclient_entry.h @@ -78,7 +78,7 @@ * SOURCE */ struct SilcClientEntryStruct { - char nickname[128 + 1]; /* Nickname */ + char nickname[256 + 1]; /* Nickname */ char username[128 + 1]; /* Username */ char hostname[256 + 1]; /* Hostname */ char server [256 + 1]; /* SILC server name */ @@ -124,6 +124,7 @@ struct SilcClientEntryStruct { */ struct SilcChannelEntryStruct { char *channel_name; /* Channel name */ + char server[256 + 1]; /* SILC server name */ char *topic; /* Current topic, may be NULL */ SilcPublicKey founder_key; /* Founder key, may be NULL */ SilcDList channel_pubkeys; /* Channel public keys, may be NULL */ -- 2.24.0