+ /** Wait for command reply */
+ silc_fsm_next(fsm, silc_client_command_reply_wait);
+ return SILC_FSM_CONTINUE;
+}
+
+/********************************* SERVICE **********************************/
+
+/* Command SERVICE. Negotiates service agreement with server. */
+/* XXX incomplete */
+
+SILC_FSM_STATE(silc_client_command_service)
+{
+ SilcClientCommandContext cmd = fsm_context;
+#if 0
+ SilcClientConnection conn = cmd->conn;
+ SilcBuffer buffer;
+ char *name;
+
+ if (cmd->argc < 2) {
+ SAY(conn->client, conn, SILC_CLIENT_MESSAGE_INFO,
+ "Usage: /SERVICE [<service name>] [-pubkey]");
+ COMMAND_ERROR(SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ return SILC_FSM_FINISH;
+ }
+
+ name = cmd->argv[1];
+
+ /* Send SERVICE command to the server */
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_SERVICE,
+ ++conn->cmd_ident, 1,
+ 1, name, strlen(name));
+ silc_client_packet_send(conn->client, conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL, buffer->data,
+ buffer->len, TRUE);
+ silc_buffer_free(buffer);
+#endif /* 0 */
+
+ /* Notify application */
+ COMMAND(SILC_STATUS_OK);
+
+ /** Wait for command reply */
+ silc_fsm_next(fsm, silc_client_command_reply_wait);
+ return SILC_FSM_CONTINUE;
+}
+
+/* Register all default commands provided by the client library for the
+ application. */
+
+void silc_client_commands_register(SilcClient client)
+{
+ silc_list_init(client->internal->commands, struct SilcClientCommandStruct,
+ next);
+
+ SILC_CLIENT_CMD(whois, WHOIS, "WHOIS", 5);
+ SILC_CLIENT_CMD(whowas, WHOWAS, "WHOWAS", 3);
+ SILC_CLIENT_CMD(identify, IDENTIFY, "IDENTIFY", 3);
+ SILC_CLIENT_CMD(nick, NICK, "NICK", 2);
+ SILC_CLIENT_CMD(list, LIST, "LIST", 2);
+ SILC_CLIENT_CMD(topic, TOPIC, "TOPIC", 3);
+ SILC_CLIENT_CMD(invite, INVITE, "INVITE", 3);
+ SILC_CLIENT_CMD(quit, QUIT, "QUIT", 2);
+ SILC_CLIENT_CMD(kill, KILL, "KILL", 4);
+ SILC_CLIENT_CMD(info, INFO, "INFO", 2);
+ SILC_CLIENT_CMD(stats, STATS, "STATS", 0);
+ SILC_CLIENT_CMD(ping, PING, "PING", 2);
+ SILC_CLIENT_CMD(oper, OPER, "OPER", 3);
+ SILC_CLIENT_CMD(join, JOIN, "JOIN", 9);
+ SILC_CLIENT_CMD(motd, MOTD, "MOTD", 2);
+ SILC_CLIENT_CMD(umode, UMODE, "UMODE", 2);
+ SILC_CLIENT_CMD(cmode, CMODE, "CMODE", 6);
+ SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", 9);
+ SILC_CLIENT_CMD(kick, KICK, "KICK", 4);
+ SILC_CLIENT_CMD(ban, BAN, "BAN", 3);
+ SILC_CLIENT_CMD(detach, DETACH, "DETACH", 0);
+ SILC_CLIENT_CMD(watch, WATCH, "WATCH", 3);
+ SILC_CLIENT_CMD(silcoper, SILCOPER, "SILCOPER", 3);
+ SILC_CLIENT_CMD(leave, LEAVE, "LEAVE", 2);
+ SILC_CLIENT_CMD(users, USERS, "USERS", 2);
+ SILC_CLIENT_CMD(getkey, GETKEY, "GETKEY", 2);
+ SILC_CLIENT_CMD(service, SERVICE, "SERVICE", 10);
+}
+
+/* Unregister all commands. */
+
+void silc_client_commands_unregister(SilcClient client)
+{
+ SILC_CLIENT_CMDU(whois, WHOIS, "WHOIS");
+ SILC_CLIENT_CMDU(whowas, WHOWAS, "WHOWAS");
+ SILC_CLIENT_CMDU(identify, IDENTIFY, "IDENTIFY");
+ SILC_CLIENT_CMDU(nick, NICK, "NICK");
+ SILC_CLIENT_CMDU(list, LIST, "LIST");
+ SILC_CLIENT_CMDU(topic, TOPIC, "TOPIC");
+ SILC_CLIENT_CMDU(invite, INVITE, "INVITE");
+ SILC_CLIENT_CMDU(quit, QUIT, "QUIT");
+ SILC_CLIENT_CMDU(kill, KILL, "KILL");
+ SILC_CLIENT_CMDU(info, INFO, "INFO");
+ SILC_CLIENT_CMDU(stats, STATS, "STATS");
+ SILC_CLIENT_CMDU(ping, PING, "PING");
+ SILC_CLIENT_CMDU(oper, OPER, "OPER");
+ SILC_CLIENT_CMDU(join, JOIN, "JOIN");
+ SILC_CLIENT_CMDU(motd, MOTD, "MOTD");
+ SILC_CLIENT_CMDU(umode, UMODE, "UMODE");
+ SILC_CLIENT_CMDU(cmode, CMODE, "CMODE");
+ SILC_CLIENT_CMDU(cumode, CUMODE, "CUMODE");
+ SILC_CLIENT_CMDU(kick, KICK, "KICK");
+ SILC_CLIENT_CMDU(ban, BAN, "BAN");
+ SILC_CLIENT_CMDU(detach, DETACH, "DETACH");
+ SILC_CLIENT_CMDU(watch, WATCH, "WATCH");
+ SILC_CLIENT_CMDU(silcoper, SILCOPER, "SILCOPER");
+ SILC_CLIENT_CMDU(leave, LEAVE, "LEAVE");
+ SILC_CLIENT_CMDU(users, USERS, "USERS");
+ SILC_CLIENT_CMDU(getkey, GETKEY, "GETKEY");
+ SILC_CLIENT_CMDU(service, SERVICE, "SERVICE");
+}
+
+/****************** Client Side Incoming Command Handling *******************/
+
+typedef struct {
+ SilcClientConnection conn;
+ SilcUInt16 cmd_ident;
+} *SilcClientProcessWhois;
+
+/* Send reply to WHOIS from server */
+
+static void
+silc_client_command_process_whois_send(SilcBool success,
+ const unsigned char *data,
+ SilcUInt32 data_len, void *context)
+{
+ SilcClientProcessWhois w = context;
+ SilcBufferStruct buffer;
+ SilcBuffer packet;
+
+ if (!data) {
+ silc_free(w);
+ return;
+ }
+
+ silc_buffer_set(&buffer, (unsigned char *)data, data_len);
+
+ /* Send the attributes back in COMMAND_REPLY packet */
+ packet =
+ silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
+ SILC_STATUS_OK, 0, w->cmd_ident,
+ 1, 11, buffer.data,
+ silc_buffer_len(&buffer));
+ if (!packet) {
+ silc_free(w);
+ return;
+ }
+
+ SILC_LOG_DEBUG(("Sending back requested WHOIS attributes"));
+
+ silc_packet_send(w->conn->stream, SILC_PACKET_COMMAND_REPLY, 0,
+ silc_buffer_datalen(packet));
+
+ silc_buffer_free(packet);
+ silc_free(w);
+}
+
+/* Process WHOIS command from server */
+
+static void silc_client_command_process_whois(SilcClient client,
+ SilcClientConnection conn,
+ SilcCommandPayload payload,
+ SilcArgumentPayload args)
+{
+ SilcClientProcessWhois w;
+ SilcDList attrs;
+ unsigned char *tmp;
+ SilcUInt32 tmp_len;
+
+ SILC_LOG_DEBUG(("Received WHOIS command"));
+
+ /* Try to take the Requested Attributes */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp)
+ return;
+
+ attrs = silc_attribute_payload_parse(tmp, tmp_len);
+ if (!attrs)
+ return;
+
+ w = silc_calloc(1, sizeof(*w));
+ if (!w) {
+ silc_attribute_payload_list_free(attrs);
+ return;
+ }
+ w->conn = conn;
+ w->cmd_ident = silc_command_get_ident(payload);
+
+ /* Process requested attributes */
+ silc_client_attributes_process(client, conn, attrs,
+ silc_client_command_process_whois_send, w);
+ silc_attribute_payload_list_free(attrs);
+}
+
+/* Client is able to receive some command packets even though they are
+ special case. Server may send WHOIS command to the client to retrieve
+ Requested Attributes information for WHOIS query the server is
+ processing. This function currently handles only the WHOIS command,
+ but if in the future more commands may arrive then this can be made
+ to support other commands too. */
+
+SILC_FSM_STATE(silc_client_command)
+{
+ SilcClientConnection conn = fsm_context;
+ SilcClient client = conn->client;
+ SilcPacket packet = state_context;
+ SilcCommandPayload payload;
+ SilcCommand command;
+ SilcArgumentPayload args;
+
+ /* Get command payload from packet */
+ payload = silc_command_payload_parse(packet->buffer.data,
+ silc_buffer_len(&packet->buffer));
+ if (!payload) {
+ SILC_LOG_DEBUG(("Bad command packet"));
+ return SILC_FSM_FINISH;
+ }
+
+ /* Get arguments */
+ args = silc_command_get_args(payload);
+
+ /* Get the command */
+ command = silc_command_get(payload);
+ switch (command) {
+
+ case SILC_COMMAND_WHOIS:
+ /* Ignore everything if requested by application */
+ if (conn->internal->params.ignore_requested_attributes)
+ break;
+
+ silc_client_command_process_whois(client, conn, payload, args);
+ break;
+
+ default:
+ break;
+ }
+
+ silc_command_payload_free(payload);
+ return SILC_FSM_FINISH;