From: Pekka Riikonen Date: Sun, 18 Mar 2007 15:47:57 +0000 (+0000) Subject: Fixed nickname parsing with WHOIS command to accept formatted X-Git-Tag: silc.toolkit.1.1.beta1~55 X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=commitdiff_plain;h=573d5cb3f242157b500dd4af26e41ce9919dedc6 Fixed nickname parsing with WHOIS command to accept formatted nicknames. Changed the silc_client_get_clients_local to allow the searched nickname to be formatted nickname. Removed %s and %S nickname formatters. Added silc_client_nickname_parse to Client library API. --- diff --git a/lib/silcclient/client_entry.c b/lib/silcclient/client_entry.c index dfbe9fae..b799d82d 100644 --- a/lib/silcclient/client_entry.c +++ b/lib/silcclient/client_entry.c @@ -62,31 +62,47 @@ SilcClientEntry silc_client_get_client_by_id(SilcClient client, /* Finds clients by nickname from local cache. */ -SilcDList silc_client_get_clients_local(SilcClient client, - SilcClientConnection conn, - const char *nickname, - const char *format) +SilcDList silc_client_get_clients_local_ext(SilcClient client, + SilcClientConnection conn, + const char *nickname, + SilcBool get_all, + SilcBool get_valid) { SilcIDCacheEntry id_cache; SilcList list; SilcDList clients; SilcClientEntry entry; - char *nicknamec; + char *nicknamec, *parsed = NULL, *format = NULL; if (!client || !conn || !nickname) return NULL; - SILC_LOG_DEBUG(("Find clients by nickname %s", nickname)); + /* Parse nickname if it is formatted */ + if (!silc_client_nickname_parse(client, conn, (char *)nickname, &parsed)) + return NULL; + + if (!get_all && parsed) + format = (char *)nickname; + if (!parsed) { + parsed = silc_memdup(nickname, strlen(nickname)); + if (!parsed) + return NULL; + } + + SILC_LOG_DEBUG(("Find clients by nickname %s", parsed)); /* Normalize nickname for search */ - nicknamec = silc_identifier_check(nickname, strlen(nickname), + nicknamec = silc_identifier_check(parsed, strlen(parsed), SILC_STRING_UTF8, 128, NULL); - if (!nicknamec) + if (!nicknamec) { + silc_free(parsed); return NULL; + } clients = silc_dlist_init(); if (!clients) { silc_free(nicknamec); + silc_free(parsed); return NULL; } @@ -98,41 +114,64 @@ SilcDList silc_client_get_clients_local(SilcClient client, &list)) { silc_mutex_unlock(conn->internal->lock); silc_free(nicknamec); + silc_free(parsed); silc_dlist_uninit(clients); return NULL; } + silc_list_start(list); - if (!format) { + if (!format && get_all) { /* Take all without any further checking */ - silc_list_start(list); while ((id_cache = silc_list_get(list))) { entry = id_cache->context; - if (entry->internal.valid) { + if (!get_valid || entry->internal.valid) { silc_client_ref_client(client, conn, id_cache->context); silc_dlist_add(clients, id_cache->context); } } } else { /* Check multiple cache entries for exact match */ - silc_list_start(list); while ((id_cache = silc_list_get(list))) { entry = id_cache->context; - if (silc_utf8_strcasecmp(entry->nickname, format) && - entry->internal.valid) { + if (silc_utf8_strcasecmp(entry->nickname, + format ? format : parsed) && + (!get_valid || entry->internal.valid)) { silc_client_ref_client(client, conn, entry); silc_dlist_add(clients, entry); + + /* If format is NULL, we find one exact match with the base + nickname (parsed). */ + if (!format) + break; } } } silc_mutex_unlock(conn->internal->lock); - silc_dlist_start(clients); - silc_free(nicknamec); + silc_free(parsed); + + if (!silc_dlist_count(clients)) { + silc_dlist_uninit(clients); + return NULL; + } + + silc_dlist_start(clients); return clients; } +/* Finds clients by nickname from local cache. */ + +SilcDList silc_client_get_clients_local(SilcClient client, + SilcClientConnection conn, + const char *nickname, + SilcBool return_all) +{ + return silc_client_get_clients_local_ext(client, conn, nickname, return_all, + TRUE); +} + /********************** Client Resolving from Server ************************/ /* Resolving context */ @@ -1051,8 +1090,9 @@ SilcClientEntry silc_client_nickname_format(SilcClient client, /* Get all clients with same nickname. Do not perform the formatting if there aren't any clients with same nickname unless the application is forcing us to do so. */ - clients = silc_client_get_clients_local(client, conn, - client_entry->nickname, NULL); + clients = silc_client_get_clients_local_ext(client, conn, + client_entry->nickname, + TRUE, FALSE); if (!clients) return NULL; if (silc_dlist_count(clients) == 1 && @@ -1118,22 +1158,6 @@ SilcClientEntry silc_client_nickname_format(SilcClient client, memcpy(&newnick[off], client_entry->hostname, len); off += len; break; - case 's': - /* Stripped server name */ - if (!client_entry->server) - break; - len = strcspn(client_entry->server, "."); - memcpy(&newnick[off], client_entry->server, len); - off += len; - break; - case 'S': - /* Full server name */ - if (!client_entry->server) - break; - len = strlen(client_entry->server); - memcpy(&newnick[off], client_entry->server, len); - off += len; - break; case 'a': /* Ascending number */ { @@ -1189,8 +1213,10 @@ SilcBool silc_client_nickname_parse(SilcClient client, SilcBool n = FALSE; int len; - if (!client->internal->params->nickname_format[0]) + if (!client->internal->params->nickname_format[0]) { + *ret_nick = NULL; return TRUE; + } if (!nickname || !nickname[0]) return FALSE; @@ -1209,8 +1235,6 @@ SilcBool silc_client_nickname_parse(SilcClient client, case 'h': case 'H': - case 's': - case 'S': case 'a': break; @@ -1223,7 +1247,7 @@ SilcBool silc_client_nickname_parse(SilcClient client, break; } - cp++; + cp++; } if (!n) return FALSE; diff --git a/lib/silcclient/client_entry.h b/lib/silcclient/client_entry.h index 7aef2860..1987caa7 100644 --- a/lib/silcclient/client_entry.h +++ b/lib/silcclient/client_entry.h @@ -70,10 +70,6 @@ void silc_client_update_server(SilcClient client, const char *server_info); SilcBool silc_client_del_server(SilcClient client, SilcClientConnection conn, SilcServerEntry server); -SilcBool silc_client_nickname_parse(SilcClient client, - SilcClientConnection conn, - char *nickname, - char **ret_nick); SilcUInt16 silc_client_get_clients_by_list(SilcClient client, SilcClientConnection conn, SilcUInt32 list_count, diff --git a/lib/silcclient/command.c b/lib/silcclient/command.c index f221b374..88bd9411 100644 --- a/lib/silcclient/command.c +++ b/lib/silcclient/command.c @@ -636,6 +636,7 @@ SILC_FSM_STATE(silc_client_command_whois) unsigned char count[4], *tmp = NULL; SilcBool details = FALSE, nick = FALSE; unsigned char *pubkey = NULL; + char *nickname = NULL; int i; /* Given without arguments fetches client's own information */ @@ -728,12 +729,17 @@ SILC_FSM_STATE(silc_client_command_whois) &obj, sizeof(obj)); } + silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname); + if (!nickname) + nickname = strdup(cmd->argv[1]); + /* Send command */ silc_client_command_send_va(conn, cmd, cmd->cmd, NULL, NULL, - 3, 1, nick ? cmd->argv[1] : NULL, - nick ? cmd->argv_lens[1] : 0, + 3, 1, nick ? nickname : NULL, + nick ? strlen(nickname) : 0, 2, tmp ? tmp : NULL, tmp ? 4 : 0, 3, silc_buffer_datalen(attrs)); + silc_free(nickname); /* Notify application */ COMMAND(SILC_STATUS_OK); @@ -1037,13 +1043,12 @@ SILC_FSM_STATE(silc_client_command_invite) silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname); /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[2]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[2], + FALSE); if (!clients) /* Resolve client information */ SILC_FSM_CALL(silc_client_get_clients( - client, conn, nickname, - cmd->argv[2], + client, conn, nickname, NULL, silc_client_command_resolve_continue, cmd)); @@ -1185,12 +1190,10 @@ SILC_FSM_STATE(silc_client_command_kill) return SILC_FSM_FINISH; /* Get the target client */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[1]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[1], FALSE); if (!clients) /* Resolve client information */ - SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, - cmd->argv[1], + SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, NULL, silc_client_command_resolve_continue, cmd)); @@ -1961,11 +1964,10 @@ SILC_FSM_STATE(silc_client_command_cumode) silc_client_nickname_parse(client, conn, cmd->argv[3], &nickname); /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[3]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[3], FALSE); if (!clients) /* Resolve client information */ - SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, cmd->argv[3], + SILC_FSM_CALL(silc_client_get_clients(client, conn, nickname, NULL, silc_client_command_resolve_continue, cmd)); @@ -2111,7 +2113,6 @@ SILC_FSM_STATE(silc_client_command_kick) SilcClientEntry target; SilcDList clients = NULL; char *name; - char *nickname = NULL; if (cmd->argc < 3) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, @@ -2142,12 +2143,8 @@ SILC_FSM_STATE(silc_client_command_kick) goto out; } - /* Parse the typed nickname. */ - silc_client_nickname_parse(client, conn, cmd->argv[2], &nickname); - /* Get the target client */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[2]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[2], FALSE); if (!clients) { SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO, "No such client: %s", cmd->argv[2]); @@ -2171,7 +2168,6 @@ SILC_FSM_STATE(silc_client_command_kick) silc_buffer_free(idp); silc_buffer_free(idp2); - silc_free(nickname); silc_client_list_free(client, conn, clients); silc_client_unref_channel(client, conn, channel); @@ -2184,7 +2180,6 @@ SILC_FSM_STATE(silc_client_command_kick) out: silc_client_unref_channel(client, conn, channel); - silc_free(nickname); return SILC_FSM_FINISH; } @@ -2622,7 +2617,6 @@ SILC_FSM_STATE(silc_client_command_getkey) SilcClientEntry client_entry; SilcServerEntry server_entry; SilcDList clients; - char *nickname = NULL; SilcBuffer idp; if (cmd->argc < 2) { @@ -2632,15 +2626,8 @@ SILC_FSM_STATE(silc_client_command_getkey) return SILC_FSM_FINISH; } - /* Parse the typed nickname. */ - if (!silc_client_nickname_parse(client, conn, cmd->argv[1], &nickname)) { - COMMAND_ERROR(SILC_STATUS_ERR_RESOURCE_LIMIT); - return SILC_FSM_FINISH; - } - /* Find client entry */ - clients = silc_client_get_clients_local(client, conn, nickname, - cmd->argv[1]); + clients = silc_client_get_clients_local(client, conn, cmd->argv[1], FALSE); if (!clients) { /* Check whether user requested server */ server_entry = silc_client_get_server(client, conn, cmd->argv[1]); @@ -2678,7 +2665,6 @@ SILC_FSM_STATE(silc_client_command_getkey) 1, silc_buffer_datalen(idp)); silc_buffer_free(idp); - silc_free(nickname); /* Notify application */ COMMAND(SILC_STATUS_OK); diff --git a/lib/silcclient/silcclient.h b/lib/silcclient/silcclient.h index 26d7b1d4..6de07125 100644 --- a/lib/silcclient/silcclient.h +++ b/lib/silcclient/silcclient.h @@ -672,20 +672,18 @@ typedef struct { Following format types are available: %n nickname - the real nickname returned by the server (mandatory) + %a number - ascending number in case there are several + same nicknames (fe. nick#2 and nick#3) %h hostname - the stripped hostname of the client %H full hostname - the full hostname of the client - %s server name - the server name the client is connected - %S full server - the full server name the client is connected - %a number - ascending number in case there are several - same nicknames (fe. nick@host and nick@host2) - Example format strings: "%n@%h%a" (fe. nick@host, nick@host2) - "%a!%n@%s" (fe. nick@server, 2!nick@server) - "%n@%H" (fe. nick@host.domain.com) + 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) 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 + '%n' without separators (such ash '#'). Also note that the separator character should be a character that cannot be part of normal nickname. */ char nickname_format[32]; @@ -2409,6 +2407,30 @@ SilcClientEntry silc_client_nickname_format(SilcClient client, SilcClientEntry client_entry, SilcBool priority); +/****f* silcclient/SilcClientAPI/silc_client_nickname_parse + * + * SYNOPSIS + * + * SilcBool silc_client_nickname_parse(SilcClient client, + * SilcClientConnection conn, + * char *nickname, + * char **ret_nick); + * + * DESCRIPTION + * + * Parses the `nickname' according to the format string given in the + * SilcClientParams. Returns the parsed nickname into the `ret_nick'. + * The caller must free the returned pointer. Returns FALSE if error + * occurred during parsing. Returns TRUE if the nickname was parsed, + * it was not formatted or if the format string has not been specified + * in SilcClientParams. + * + ***/ +SilcBool silc_client_nickname_parse(SilcClient client, + SilcClientConnection conn, + char *nickname, + char **ret_nick); + #ifdef __cplusplus } #endif diff --git a/lib/silcclient/silcclient_entry.h b/lib/silcclient/silcclient_entry.h index 6ebe4129..20f6e9e3 100644 --- a/lib/silcclient/silcclient_entry.h +++ b/lib/silcclient/silcclient_entry.h @@ -325,8 +325,10 @@ void silc_client_list_free(SilcClient client, SilcClientConnection conn, * completion callback will be called when the client entries has been * found. After the server returns the client information it is cached * and can be accesses locally at a later time. The resolving is done - * with IDENTIFY command. The `server' may be NULL. Returns 0 on - * error and the command identifier used with the command otherwise. + * with IDENTIFY command. The `server' may be NULL. The server + * associated with the nickname may be in the `nickname' (nick@server). + * Returns 0 on error and the command identifier used with the command + * otherwise. * * NOTES * @@ -368,8 +370,10 @@ SilcUInt16 silc_client_get_clients(SilcClient client, * completion callback will be called when the client entries has been * found. After the server returns the client information it is cached * and can be accesses locally at a later time. The resolving is done - * with WHOIS command. The `server' may be NULL. Returns 0 on error, - * and the command identifier used with the command otherwise. + * with WHOIS command. The `server' may be NULL. The server + * associated with the nickname may be in the `nickname' (nick@server). + * Returns 0 on error and the command identifier used with the command + * otherwise. * * If the `attributes' is non-NULL then the buffer includes Requested * Attributes which can be used to fetch very detailed information @@ -400,19 +404,20 @@ SilcUInt16 silc_client_get_clients_whois(SilcClient client, * SilcDList silc_client_get_clients_local(SilcClient client, * SilcClientConnection conn, * const char *nickname, - * const char *format); + * SilcBool return_all); * * DESCRIPTION * * Same as silc_client_get_clients function but does not resolve anything - * from the server. This checks local cache and returns all matching - * clients from the local cache. If none was found this returns NULL. - * The `nickname' is the real nickname of the client, and the `format' - * is the formatted nickname to find exact match from multiple found - * entries. The format must be same as given in the SilcClientParams - * structure to the client library. If the `format' is NULL all found - * clients by `nickname' are returned. The caller must free the - * returned list by silc_client_list_free function. + * from the server. This checks local cache and returns matching clients + * from the local cache. If none was found this returns NULL. The + * `nickname' is the nickname to find and it may be a formatted nickname + * or a base nickname. If the `return_all' is TRUE this call will return + * all clients matching the `nickname' base. If it is FALSE this will + * return the exact match if `nickname' is a formatted nickname or the + * first matching nickname if it is not formatted. The formatted nickname + * must of the format specified in SilcClientParams. The caller must free + * the returned list by calling silc_client_list_free function. * * NOTES * @@ -427,7 +432,7 @@ SilcUInt16 silc_client_get_clients_whois(SilcClient client, SilcDList silc_client_get_clients_local(SilcClient client, SilcClientConnection conn, const char *nickname, - const char *format); + SilcBool return_all); /****f* silcclient/SilcClientAPI/silc_client_get_clients_by_channel *