コード例 #1
0
ファイル: buddy.c プロジェクト: dylex/pidgin
static void
silcpurple_buddy_resetkey(PurpleBlistNode *node, gpointer data)
{
	PurpleBuddy *b;
	PurpleConnection *gc;
        SilcPurple sg;
	char *nickname;
	SilcClientEntry *clients;
	SilcUInt32 clients_count;

	g_return_if_fail(PURPLE_BLIST_NODE_IS_BUDDY(node));

	b = (PurpleBuddy *) node;
	gc = purple_account_get_connection(b->account);
	sg = gc->proto_data;

	if (!silc_parse_userfqdn(b->name, &nickname, NULL))
		return;

	/* Find client entry */
	clients = silc_client_get_clients_local(sg->client, sg->conn,
						nickname, b->name,
						&clients_count);
	if (!clients) {
		silc_free(nickname);
		return;
	}

	clients[0]->prv_resp = FALSE;
	silc_client_del_private_message_key(sg->client, sg->conn,
					    clients[0]);
	silc_free(clients);
	silc_free(nickname);
}
コード例 #2
0
ファイル: idlist.c プロジェクト: FabrizioFabbe/silc
SilcClientEntry
silc_idlist_add_client(SilcIDList id_list, char *nickname, char *username,
		       char *userinfo, SilcClientID *id,
		       SilcServerEntry router, void *connection)
{
  SilcClientEntry client;
  char *nicknamec = NULL;

  SILC_LOG_DEBUG(("Adding new client entry"));

  /* Normalize name.  This is cached, original is in client context.  */
  if (nickname) {
    nicknamec = silc_identifier_check(nickname, strlen(nickname),
				      SILC_STRING_UTF8, 128, NULL);
    if (!nicknamec)
      return NULL;
  }

  /* Check username. */
  if (username) {
    char u[128 + 1], h[256 + 1];
    int ret;

    ret = silc_parse_userfqdn(username, u, sizeof(u), h, sizeof(h));
    if (!ret)
      return NULL;
    if (!silc_identifier_verify(u, strlen(u), SILC_STRING_UTF8, 128))
      return NULL;
    if (ret > 1 && !silc_identifier_verify(h, strlen(h),
					   SILC_STRING_UTF8, 256))
      return NULL;
  }

  client = silc_calloc(1, sizeof(*client));
  if (!client)
    return NULL;
  client->nickname = nickname;
  client->username = username ? strdup(username) : NULL;
  client->userinfo = userinfo;
  client->id = id;
  client->router = router;
  client->connection = connection;
  client->channels = silc_hash_table_alloc(3, silc_hash_ptr, NULL,
					   NULL, NULL, NULL, NULL, TRUE);

  if (!silc_idcache_add(id_list->clients, nicknamec, (void *)client->id,
			(void *)client)) {
    silc_hash_table_free(client->channels);
    silc_free(client);
    silc_free(nicknamec);
    return NULL;
  }

  return client;
}
コード例 #3
0
ファイル: ft.c プロジェクト: neerajvashistha/libpurple
PurpleXfer *silcpurple_ftp_new_xfer(PurpleConnection *gc, const char *name)
{
    SilcPurple sg = gc->proto_data;
    SilcClient client = sg->client;
    SilcClientConnection conn = sg->conn;
    SilcClientEntry *clients;
    SilcUInt32 clients_count;
    SilcPurpleXfer xfer;
    char *nickname;

    g_return_val_if_fail(name != NULL, NULL);

    if (!silc_parse_userfqdn(name, &nickname, NULL))
        return NULL;

    /* Find client entry */
    clients = silc_client_get_clients_local(client, conn, nickname, name,
                                            &clients_count);
    if (!clients) {
        silc_client_get_clients(client, conn, nickname, NULL,
                                silcpurple_ftp_send_file_resolved,
                                strdup(name));
        silc_free(nickname);
        return NULL;
    }

    xfer = silc_calloc(1, sizeof(*xfer));

    g_return_val_if_fail(xfer != NULL, NULL);

    xfer->sg = sg;
    xfer->client_entry = clients[0];
    xfer->xfer = purple_xfer_new(xfer->sg->account, PURPLE_XFER_SEND,
                                 xfer->client_entry->nickname);
    if (!xfer->xfer) {
        silc_client_file_close(xfer->sg->client, xfer->sg->conn, xfer->session_id);
        g_free(xfer->hostname);
        silc_free(xfer);
        return NULL;
    }
    purple_xfer_set_init_fnc(xfer->xfer, silcpurple_ftp_send);
    purple_xfer_set_request_denied_fnc(xfer->xfer, silcpurple_ftp_request_denied);
    purple_xfer_set_cancel_send_fnc(xfer->xfer, silcpurple_ftp_send_cancel);
    xfer->xfer->data = xfer;

    silc_free(clients);
    silc_free(nickname);

    return xfer->xfer;
}
コード例 #4
0
ファイル: buddy.c プロジェクト: dylex/pidgin
static void
silcpurple_buddy_getkey(PurpleConnection *gc, const char *name)
{
	SilcPurple sg = gc->proto_data;
	SilcClient client = sg->client;
	SilcClientConnection conn = sg->conn;
	SilcClientEntry *clients;
	SilcUInt32 clients_count;
	SilcPurpleBuddyGetkey g;
	char *nickname;

	if (!name)
		return;

	if (!silc_parse_userfqdn(name, &nickname, NULL))
		return;

	/* Find client entry */
	clients = silc_client_get_clients_local(client, conn, nickname, name,
						&clients_count);
	if (!clients) {
		silc_client_get_clients(client, conn, nickname, NULL,
					silcpurple_buddy_getkey_resolved,
					g_strdup(name));
		silc_free(nickname);
		return;
	}

	/* Call GETKEY */
	g = silc_calloc(1, sizeof(*g));
	if (!g)
		return;
	g->client = client;
	g->conn = conn;
	g->client_id = *clients[0]->id;
	silc_client_command_call(client, conn, NULL, "GETKEY",
				 clients[0]->nickname, NULL);
	silc_client_command_pending(conn, SILC_COMMAND_GETKEY,
				    conn->cmd_ident,
				    (SilcCommandCb)silcpurple_buddy_getkey_cb, g);
	silc_free(clients);
	silc_free(nickname);
}
コード例 #5
0
ファイル: buddy.c プロジェクト: dylex/pidgin
static void
silcpurple_buddy_privkey(PurpleConnection *gc, const char *name)
{
	SilcPurple sg = gc->proto_data;
	char *nickname;
	SilcPurplePrivkey p;
	SilcClientEntry *clients;
	SilcUInt32 clients_count;

	if (!name)
		return;
	if (!silc_parse_userfqdn(name, &nickname, NULL))
		return;

	/* Find client entry */
	clients = silc_client_get_clients_local(sg->client, sg->conn,
						nickname, name,
						&clients_count);
	if (!clients) {
		silc_client_get_clients(sg->client, sg->conn, nickname, NULL,
					silcpurple_buddy_privkey_resolved,
					g_strdup(name));
		silc_free(nickname);
		return;
	}

	p = silc_calloc(1, sizeof(*p));
	if (!p)
		return;
	p->client = sg->client;
	p->conn = sg->conn;
	p->client_id = *clients[0]->id;
	purple_request_input(gc, _("IM With Password"), NULL,
	                     _("Set IM Password"), NULL, FALSE, TRUE, NULL,
	                     _("OK"), G_CALLBACK(silcpurple_buddy_privkey_cb),
	                     _("Cancel"), G_CALLBACK(silcpurple_buddy_privkey_cb),
	                     gc->account, NULL, NULL, p);

	silc_free(clients);
	silc_free(nickname);
}
コード例 #6
0
ファイル: buddy.c プロジェクト: dylex/pidgin
static void
silcpurple_buddy_keyagr_do(PurpleConnection *gc, const char *name,
			 gboolean force_local)
{
	SilcPurple sg = gc->proto_data;
	SilcClientEntry *clients;
	SilcUInt32 clients_count;
	char *local_ip = NULL, *remote_ip = NULL;
	gboolean local = TRUE;
	char *nickname;
	SilcPurpleKeyAgr a;

	if (!sg->conn || !name)
		return;

	if (!silc_parse_userfqdn(name, &nickname, NULL))
		return;

	/* Find client entry */
	clients = silc_client_get_clients_local(sg->client, sg->conn, nickname, name,
						&clients_count);
	if (!clients) {
		/* Resolve unknown user */
		SilcPurpleResolve r = silc_calloc(1, sizeof(*r));
		if (!r)
			return;
		r->nick = g_strdup(name);
		r->gc = gc;
		silc_client_get_clients(sg->client, sg->conn, nickname, NULL,
					silcpurple_buddy_keyagr_resolved, r);
		silc_free(nickname);
		return;
	}

	/* Resolve the local IP from the outgoing socket connection.  We resolve
	   it to check whether we have a private range IP address or public IP
	   address.  If we have public then we will assume that we are not behind
	   NAT and will provide automatically the point of connection to the
	   agreement.  If we have private range address we assume that we are
	   behind NAT and we let the responder provide the point of connection.

	   The algorithm also checks the remote IP address of server connection.
	   If it is private range address and we have private range address we
	   assume that we are chatting in LAN and will provide the point of
	   connection.

	   Naturally this algorithm does not always get things right. */

	if (silc_net_check_local_by_sock(sg->conn->sock->sock, NULL, &local_ip)) {
		/* Check if the IP is private */
		if (!force_local && silcpurple_ip_is_private(local_ip)) {
			local = FALSE;

			/* Local IP is private, resolve the remote server IP to see whether
			   we are talking to Internet or just on LAN. */
			if (silc_net_check_host_by_sock(sg->conn->sock->sock, NULL,
							&remote_ip))
				if (silcpurple_ip_is_private(remote_ip))
					/* We assume we are in LAN.  Let's provide
					   the connection point. */
					local = TRUE;
		}
	}

	if (force_local)
		local = TRUE;

	if (local && !local_ip)
		local_ip = silc_net_localip();

	a = silc_calloc(1, sizeof(*a));
	if (!a)
		return;
	a->responder = local;

	/* Send the key agreement request */
	silc_client_send_key_agreement(sg->client, sg->conn, clients[0],
				       local ? local_ip : NULL, NULL, 0, 60,
				       silcpurple_buddy_keyagr_cb, a);

	silc_free(local_ip);
	silc_free(remote_ip);
	silc_free(clients);
}
コード例 #7
0
ファイル: command_reply.c プロジェクト: TabTwo/silc-server
static char
silc_server_command_reply_identify_save(SilcServerCommandReplyContext cmd)
{
  SilcServer server = cmd->server;
  SilcUInt32 len, id_len;
  unsigned char *id_data;
  char *name, *info;
  SilcClientID client_id;
  SilcServerID server_id;
  SilcChannelID channel_id;
  SilcClientEntry client;
  SilcServerEntry server_entry;
  SilcChannelEntry channel;
  char global = FALSE;
  char nick[128 + 1];
  SilcIDPayload idp = NULL;
  SilcIdType id_type;

  id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
  if (!id_data)
    return FALSE;
  idp = silc_id_payload_parse(id_data, id_len);
  if (!idp)
    return FALSE;

  name = silc_argument_get_arg_type(cmd->args, 3, &len);
  info = silc_argument_get_arg_type(cmd->args, 4, &len);

  id_type = silc_id_payload_get_type(idp);

  switch (id_type) {
  case SILC_ID_CLIENT:
    if (!silc_id_payload_get_id(idp, &client_id, sizeof(client_id)))
      goto error;

    SILC_LOG_DEBUG(("Received client information"));

    client = silc_idlist_find_client_by_id(server->local_list,
					   &client_id, FALSE, NULL);
    if (!client) {
      client = silc_idlist_find_client_by_id(server->global_list, &client_id,
					     FALSE, NULL);
      global = TRUE;
    }
    if (!client) {
      /* If router did not find such Client ID in its lists then this must
	 be bogus client or some router in the net is buggy. */
      if (server->server_type != SILC_SERVER)
	goto error;

      /* Take nickname */
      if (name)
	silc_parse_userfqdn(name, nick, sizeof(nick), NULL, 0);

      /* We don't have that client anywhere, add it. The client is added
	 to global list since server didn't have it in the lists so it must be
	 global. */
      client = silc_idlist_add_client(server->global_list,
				      nick[0] ? strdup(nick) : NULL,
				      info ? strdup(info) : NULL, NULL,
				      silc_id_dup(&client_id, SILC_ID_CLIENT),
				      silc_packet_get_context(cmd->sock),
				      NULL);
      if (!client) {
	SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
	goto error;
      }

      client->data.status |= SILC_IDLIST_STATUS_REGISTERED;
      client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
      client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;

      SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
		      server->stat.clients + 1));
      server->stat.clients++;
    } else {
      /* We have the client already, update the data */

      SILC_LOG_DEBUG(("Updating client data"));

      /* Take nickname */
      if (name) {
	silc_parse_userfqdn(name, nick, sizeof(nick), NULL, 0);

	/* Check nickname */
	name = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
				     128, NULL);
	if (!name) {
	  SILC_LOG_ERROR(("Malformed nickname '%s' received in IDENTIFY "
			  "reply ", nick));
	  return FALSE;
	}

	silc_free(client->nickname);
	client->nickname = strdup(nick);

	/* Update the context */
	silc_idcache_update_by_context(global ? server->global_list->clients :
				       server->local_list->clients, client,
				       NULL, name, TRUE);
      }

      if (info) {
	silc_free(client->username);
	client->username = strdup(info);
      }

      client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
      client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
    }

    break;

  case SILC_ID_SERVER:
    if (!name)
      goto error;

    if (!silc_id_payload_get_id(idp, &server_id, sizeof(server_id)))
      goto error;

    SILC_LOG_DEBUG(("Received server information"));

    server_entry = silc_idlist_find_server_by_id(server->local_list,
						 &server_id, FALSE, NULL);
    if (!server_entry)
      server_entry = silc_idlist_find_server_by_id(server->global_list,
						   &server_id, FALSE, NULL);
    if (!server_entry) {
      /* If router did not find such Server ID in its lists then this must
	 be bogus server or some router in the net is buggy. */
      if (server->server_type != SILC_SERVER)
	goto error;

      /* We don't have that server anywhere, add it. */
      server_entry = silc_idlist_add_server(server->global_list,
					    strdup(name), 0,
					    silc_id_dup(&server_id,
							SILC_ID_SERVER),
					    server->router,
					    SILC_PRIMARY_ROUTE(server));
      if (!server_entry)
	goto error;

      server_entry->data.status |= SILC_IDLIST_STATUS_REGISTERED;
      server_entry->data.status |= SILC_IDLIST_STATUS_RESOLVED;
      server_entry->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
    }

    break;

  case SILC_ID_CHANNEL:
    if (!name)
      goto error;

    if (!silc_id_payload_get_id(idp, &channel_id, sizeof(channel_id)))
      goto error;

    SILC_LOG_DEBUG(("Received channel information"));

    /* Check channel name */
    info = silc_channel_name_check(name, strlen(name), SILC_STRING_UTF8,
				   256, NULL);
    if (!info)
      goto error;

    channel = silc_idlist_find_channel_by_name(server->local_list,
					       info, NULL);
    if (!channel)
      channel = silc_idlist_find_channel_by_name(server->global_list,
						 info, NULL);
    if (!channel) {
      /* If router did not find such Channel ID in its lists then this must
	 be bogus channel or some router in the net is buggy. */
      if (server->server_type != SILC_SERVER) {
	silc_free(info);
	goto error;
      }

      /* We don't have that channel anywhere, add it. */
      channel = silc_idlist_add_channel(server->global_list, strdup(name),
					SILC_CHANNEL_MODE_NONE,
					silc_id_dup(&channel_id,
						    SILC_ID_CHANNEL),
					server->router, NULL, NULL, 0);
      if (!channel) {
	silc_free(info);
	goto error;
      }
      silc_free(info);
    }

    break;
  }

  silc_id_payload_free(idp);
  return TRUE;

 error:
  silc_id_payload_free(idp);
  return FALSE;
}
コード例 #8
0
ファイル: command_reply.c プロジェクト: TabTwo/silc-server
static char
silc_server_command_reply_whowas_save(SilcServerCommandReplyContext cmd)
{
  SilcServer server = cmd->server;
  SilcUInt32 len, id_len;
  unsigned char *id_data;
  char *nickname, *username, *realname;
  SilcID id;
  SilcClientEntry client;
  SilcIDCacheEntry cache = NULL;
  char nick[128 + 1], servername[256 + 1], uname[128 + 1];
  int global = FALSE;
  const char *hostname, *ip;

  silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
			      NULL, &hostname, &ip, NULL);

  id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
  nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
  username = silc_argument_get_arg_type(cmd->args, 4, &len);
  if (!id_data || !nickname || !username)
    return FALSE;

  realname = silc_argument_get_arg_type(cmd->args, 5, &len);

  if (!silc_id_payload_parse_id(id_data, id_len, &id))
    return FALSE;

  /* Check if we have this client cached already. */

  client = silc_idlist_find_client_by_id(server->local_list,
					 SILC_ID_GET_ID(id),
					 FALSE, &cache);
  if (!client) {
    client = silc_idlist_find_client_by_id(server->global_list,
					   SILC_ID_GET_ID(id),
					   FALSE, &cache);
    global = TRUE;
  }

  if (!client) {
    /* If router did not find such Client ID in its lists then this must
       be bogus client or some router in the net is buggy. */
    if (server->server_type != SILC_SERVER)
      return FALSE;

    /* Take hostname out of nick string if it includes it. */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));

    /* We don't have that client anywhere, add it. The client is added
       to global list since server didn't have it in the lists so it must be
       global. */
    client = silc_idlist_add_client(server->global_list,
				    strdup(nick), username,
				    strdup(realname),
				    silc_id_dup(SILC_ID_GET_ID(id),
						SILC_ID_CLIENT),
				    silc_packet_get_context(cmd->sock), NULL);
    if (!client) {
      SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
      return FALSE;
    }

    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
    client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;
    client->servername = servername[0] ? strdup(servername) : NULL;
  } else {
    /* We have the client already, update the data */

    /* Check nickname */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));
    nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
				     128, NULL);
    if (!nickname) {
      SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOWAS reply "
		      "from %s",
		      nick, hostname ? hostname : ""));
      return FALSE;
    }

    /* Check username */
    silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0);
    if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128))
      return FALSE;

    silc_free(client->nickname);
    silc_free(client->username);
    silc_free(client->servername);

    client->nickname = strdup(nick);
    client->username = strdup(username);
    client->servername = servername[0] ? strdup(servername) : NULL;
    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
    client->data.status &= ~SILC_IDLIST_STATUS_REGISTERED;

    /* Update cache entry */
    silc_idcache_update_by_context(global ? server->global_list->clients :
				   server->local_list->clients, client, NULL,
				   nickname, TRUE);
  }

  /* If client is global and is not on any channel then add that we'll
     expire the entry after a while. */
  if (global) {
    client = silc_idlist_find_client_by_id(server->global_list, client->id,
					   FALSE, &cache);
    if (client && !silc_hash_table_count(client->channels)) {
      client->data.created = silc_time();
      silc_dlist_del(server->expired_clients, client);
      silc_dlist_add(server->expired_clients, client);
    }
  }

  return TRUE;
}
コード例 #9
0
ファイル: command_reply.c プロジェクト: TabTwo/silc-server
static char
silc_server_command_reply_whois_save(SilcServerCommandReplyContext cmd)
{
  SilcServer server = cmd->server;
  unsigned char *id_data, *umodes;
  char *nickname, *username, *realname, *tmp;
  unsigned char *fingerprint;
  SilcID id;
  SilcClientEntry client;
  char global = FALSE;
  char nick[128 + 1], servername[256 + 1], uname[128 + 1];
  SilcUInt32 mode = 0, len, len2, id_len, flen;
  const char *hostname, *ip;

  silc_socket_stream_get_info(silc_packet_stream_get_stream(cmd->sock),
			      NULL, &hostname, &ip, NULL);

  id_data = silc_argument_get_arg_type(cmd->args, 2, &id_len);
  nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
  username = silc_argument_get_arg_type(cmd->args, 4, &len);
  realname = silc_argument_get_arg_type(cmd->args, 5, &len);
  if (!id_data || !nickname || !username || !realname)
    return FALSE;

  tmp = silc_argument_get_arg_type(cmd->args, 7, &len);
  if (tmp)
    SILC_GET32_MSB(mode, tmp);

  if (!silc_id_payload_parse_id(id_data, id_len, &id))
    return FALSE;

  fingerprint = silc_argument_get_arg_type(cmd->args, 9, &flen);

  /* Check if we have this client cached already. */

  client = silc_idlist_find_client_by_id(server->local_list,
					 SILC_ID_GET_ID(id),
					 FALSE, NULL);
  if (!client) {
    client = silc_idlist_find_client_by_id(server->global_list,
					   SILC_ID_GET_ID(id),
					   FALSE, NULL);
    global = TRUE;
  }

  if (!client) {
    /* If router did not find such Client ID in its lists then this must
       be bogus client or some router in the net is buggy. */
    if (server->server_type != SILC_SERVER)
      return FALSE;

    /* Take hostname out of nick string if it includes it. */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));

    /* We don't have that client anywhere, add it. The client is added
       to global list since server didn't have it in the lists so it must be
       global. This will check for valid nickname and username strings. */
    client = silc_idlist_add_client(server->global_list,
				    strdup(nick), username,
				    strdup(realname),
				    silc_id_dup(SILC_ID_GET_ID(id),
						SILC_ID_CLIENT),
				    silc_packet_get_context(cmd->sock),
				    NULL);
    if (!client) {
      SILC_LOG_ERROR(("Could not add new client to the ID Cache"));
      return FALSE;
    }

    client->data.status |=
      (SILC_IDLIST_STATUS_REGISTERED | SILC_IDLIST_STATUS_RESOLVED);
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
    client->mode = mode;
    client->servername = servername[0] ? strdup(servername) : NULL;

    SILC_LOG_DEBUG(("stat.clients %d->%d", server->stat.clients,
		    server->stat.clients + 1));
    server->stat.clients++;
  } else {
    /* We have the client already, update the data */

    SILC_LOG_DEBUG(("Updating client data"));

    /* Check nickname */
    silc_parse_userfqdn(nickname, nick, sizeof(nick), servername,
			sizeof(servername));
    nickname = silc_identifier_check(nick, strlen(nick), SILC_STRING_UTF8,
				     128, NULL);
    if (!nickname) {
      SILC_LOG_ERROR(("Malformed nickname '%s' received in WHOIS reply "
		      "from %s",
		      hostname ? hostname : "", nick));
      return FALSE;
    }

    /* Check username */
    silc_parse_userfqdn(username, uname, sizeof(uname), NULL, 0);
    if (!silc_identifier_verify(uname, strlen(uname), SILC_STRING_UTF8, 128)) {
      SILC_LOG_ERROR(("Malformed username '%s' received in WHOIS reply "
		      "from %s",
		      hostname ? hostname : "", tmp));
      return FALSE;
    }

    /* Update entry */
    silc_idcache_update_by_context(global ? server->global_list->clients :
				   server->local_list->clients, client, NULL,
				   nickname, TRUE);

    silc_free(client->nickname);
    silc_free(client->username);
    silc_free(client->userinfo);
    silc_free(client->servername);

    client->nickname = strdup(nick);
    client->username = strdup(username);
    client->userinfo = strdup(realname);
    client->servername = servername[0] ? strdup(servername) : NULL;
    client->mode = mode;
    client->data.status |= SILC_IDLIST_STATUS_RESOLVED;
    client->data.status &= ~SILC_IDLIST_STATUS_RESOLVING;
  }

  /* 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 (fingerprint && flen == sizeof(client->data.fingerprint))
    memcpy(client->data.fingerprint, fingerprint, flen);

  /* Take Requested Attributes if set. */
  tmp = silc_argument_get_arg_type(cmd->args, 11, &len);
  if (tmp) {
    silc_free(client->attrs);
    client->attrs = silc_memdup(tmp, len);
    client->attrs_len = len;

    /* Try to take public key from attributes if present and we don't have
       the key already.  Do this only on normal server.  Routers do GETKEY
       for all clients anyway. */
    if (server->server_type != SILC_ROUTER && !client->data.public_key) {
      SilcAttributePayload attr;
      SilcAttributeObjPk pk;
      unsigned char f[SILC_HASH_MAXLEN];
      SilcDList attrs = silc_attribute_payload_parse(tmp, len);

      SILC_LOG_DEBUG(("Take client public key from attributes"));

      if (attrs) {
	silc_dlist_start(attrs);
	while ((attr = silc_dlist_get(attrs)) != SILC_LIST_END) {
	  if (silc_attribute_get_attribute(attr) ==
	      SILC_ATTRIBUTE_USER_PUBLIC_KEY) {

	    if (!silc_attribute_get_object(attr, &pk, sizeof(pk)))
	      continue;

	    /* Take only SILC public keys */
	    if (strcmp(pk.type, "silc-rsa")) {
	      silc_free(pk.type);
	      silc_free(pk.data);
	      continue;
	    }

	    /* Verify that the server provided fingerprint matches the key */
	    silc_hash_make(server->sha1hash, pk.data, pk.data_len, f);
	    if (memcmp(f, client->data.fingerprint, sizeof(f))) {
	      silc_free(pk.type);
	      silc_free(pk.data);
	      continue;
	    }

	    /* Save the public key. */
	    if (!silc_pkcs_public_key_alloc(SILC_PKCS_SILC,
					    pk.data, pk.data_len,
					    &client->data.public_key)) {
	      silc_free(pk.type);
	      silc_free(pk.data);
	      continue;
	    }

	    SILC_LOG_DEBUG(("Saved client public key from attributes"));

	    /* Add client's public key to repository */
	    if (!silc_server_get_public_key_by_client(server, client, NULL))
	      silc_skr_add_public_key_simple(server->repository,
					     client->data.public_key,
					     SILC_SKR_USAGE_IDENTIFICATION,
					     client, NULL);

	    silc_free(pk.type);
	    silc_free(pk.data);
	    break;
	  }
	}

	silc_attribute_payload_list_free(attrs);
      }
    }
  }

  return TRUE;
}