X-Git-Url: http://git.silcnet.org/gitweb/?p=silc.git;a=blobdiff_plain;f=lib%2Fsilcclient%2Fclient.c;fp=apps%2Fsilc%2Fclient.c;h=d2b4aa660420eafa56ffaf918292651712fdcd9f;hp=b3a6d391bc0c38ac1e3f220e51bea94256cbacf4;hb=318d79b391bf6288e3e28c840217a7097f3d0392;hpb=89b07a460a554eb5173fe07f09b8c51c31d53e29 diff --git a/apps/silc/client.c b/lib/silcclient/client.c similarity index 58% rename from apps/silc/client.c rename to lib/silcclient/client.c index b3a6d391..d2b4aa66 100644 --- a/apps/silc/client.c +++ b/lib/silcclient/client.c @@ -17,108 +17,36 @@ GNU General Public License for more details. */ -/* - * $Id$ - * $Log$ - * Revision 1.13 2000/07/20 10:17:25 priikone - * Added dynamic protocol registering/unregistering support. The - * patch was provided by cras. - * - * Revision 1.12 2000/07/19 07:07:34 priikone - * Save packet on private message's command context. - * - * Revision 1.11 2000/07/18 12:20:39 priikone - * Added ^U functionality, clears input line (patch form cras). - * - * Revision 1.10 2000/07/18 06:53:15 priikone - * Allow partial command strings in comparison. - * - * Revision 1.9 2000/07/14 06:13:19 priikone - * Moved all the generic packet sending, encryption, reception, - * decryption and processing functions to library as they were - * duplicated code with the server. Now client uses the generic - * routines which is a lot cleaner. - * - * Revision 1.8 2000/07/12 05:56:32 priikone - * Major rewrite of ID Cache system. Support added for the new - * ID cache system. - * - * Revision 1.7 2000/07/10 05:40:33 priikone - * Minor bug fixes. - * - * Revision 1.6 2000/07/07 06:54:16 priikone - * Print channel name when receiving channel message to non-current - * channel. - * - * Revision 1.5 2000/07/06 07:14:36 priikone - * Fixes to NAMES command handling. - * Fixes when leaving from channel. - * - * Revision 1.4 2000/07/05 06:12:05 priikone - * Global cosmetic changes. - * - * Revision 1.3 2000/07/04 08:29:12 priikone - * Added support for PING command. The ping times are calculated - * and showed to the user. - * - * Revision 1.2 2000/07/03 05:49:48 priikone - * Implemented LEAVE command. Minor bug fixes. - * - * Revision 1.1.1.1 2000/06/27 11:36:56 priikone - * Imported from internal CVS/Added Log headers. - * - * - */ - -#include "clientincludes.h" - -/* Static function prototypes */ -static int silc_client_bad_keys(unsigned char key); -static void silc_client_clear_input(SilcClient client); -static void silc_client_process_message(SilcClient client); -static char *silc_client_parse_command(unsigned char *buffer); +/* $Id$ */ + +#include "clientlibincludes.h" /* Static task callback prototypes */ -SILC_TASK_CALLBACK(silc_client_update_clock); -SILC_TASK_CALLBACK(silc_client_run_commands); -SILC_TASK_CALLBACK(silc_client_process_key_press); SILC_TASK_CALLBACK(silc_client_connect_to_server_start); SILC_TASK_CALLBACK(silc_client_connect_to_server_second); SILC_TASK_CALLBACK(silc_client_connect_to_server_final); SILC_TASK_CALLBACK(silc_client_packet_process); SILC_TASK_CALLBACK(silc_client_packet_parse_real); -SilcClientWindow silc_client_create_main_window(SilcClient client); -SilcClientWindow silc_client_add_window(SilcClient client, - int is_current); -void silc_client_packet_parse(SilcPacketParserContext *parser_context); -void silc_client_packet_parse_type(SilcClient client, - SilcSocketConnection sock, - SilcPacketContext *packet); -void silc_client_private_message_process(SilcClient client, - SilcSocketConnection sock, - SilcPacketContext *packet); - -/* Definitions from version.h */ -extern char *silc_version; -extern char *silc_name; -extern char *silc_fullname; +static void silc_client_packet_parse(SilcPacketParserContext *parser_context); +static void silc_client_packet_parse_type(SilcClient client, + SilcSocketConnection sock, + SilcPacketContext *packet); /* Allocates new client object. This has to be done before client may work. After calling this one must call silc_client_init to initialize - the client. */ + the client. The `application' is application specific user data pointer + and caller must free it. */ -int silc_client_alloc(SilcClient *new_client) +SilcClient silc_client_alloc(SilcClientOperations *ops, void *application) { + SilcClient new_client; - *new_client = silc_calloc(1, sizeof(**new_client)); - (*new_client)->input_buffer = NULL; - (*new_client)->screen = NULL; - (*new_client)->windows = NULL; - (*new_client)->windows_count = 0; - (*new_client)->current_win = NULL; + new_client = silc_calloc(1, sizeof(*new_client)); + new_client->application = application; + new_client->ops = ops; - return TRUE; + return new_client; } /* Free's client object */ @@ -136,18 +64,7 @@ void silc_client_free(SilcClient client) int silc_client_init(SilcClient client) { - SILC_LOG_DEBUG(("Initializing client")); - assert(client); - - client->username = silc_get_username(); - client->realname = silc_get_real_name(); - - /* Register all configured ciphers, PKCS and hash functions. */ - client->config->client = (void *)client; - silc_client_config_register_ciphers(client->config); - silc_client_config_register_pkcs(client->config); - silc_client_config_register_hashfuncs(client->config); /* Initialize hash functions for client to use */ silc_hash_alloc("md5", &client->md5hash); @@ -161,84 +78,14 @@ int silc_client_init(SilcClient client) silc_rng_init(client->rng); silc_math_primegen_init(); /* XXX */ - /* Load public and private key */ - if (silc_client_load_keys(client) == FALSE) - goto err0; - - /* Register the task queues. In SILC we have by default three task queues. - One task queue for non-timeout tasks which perform different kind of - I/O on file descriptors, timeout task queue for timeout tasks, and, - generic non-timeout task queue whose tasks apply to all connections. */ - silc_task_queue_alloc(&client->io_queue, TRUE); - if (!client->io_queue) { - goto err0; - } - silc_task_queue_alloc(&client->timeout_queue, TRUE); - if (!client->timeout_queue) { - goto err1; - } - silc_task_queue_alloc(&client->generic_queue, TRUE); - if (!client->generic_queue) { - goto err1; - } - /* Register protocols */ silc_client_protocols_register(); /* Initialize the scheduler */ - silc_schedule_init(client->io_queue, client->timeout_queue, - client->generic_queue, 5000); - - /* Register the main task that is used in client. This received - the key pressings. */ - if (silc_task_register(client->io_queue, fileno(stdin), - silc_client_process_key_press, - (void *)client, 0, 0, - SILC_TASK_FD, - SILC_TASK_PRI_NORMAL) == NULL) { - goto err2; - } - - /* Register timeout task that updates clock every minute. */ - if (silc_task_register(client->timeout_queue, 0, - silc_client_update_clock, - (void *)client, - silc_client_time_til_next_min(), 0, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_LOW) == NULL) { - goto err2; - } - - if (client->config->commands) { - /* Run user configured commands with timeout */ - if (silc_task_register(client->timeout_queue, 0, - silc_client_run_commands, - (void *)client, 0, 1, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_LOW) == NULL) { - goto err2; - } - } - - /* Allocate the input buffer used to save typed characters */ - client->input_buffer = silc_buffer_alloc(SILC_SCREEN_INPUT_WIN_SIZE); - silc_buffer_pull_tail(client->input_buffer, - SILC_BUFFER_END(client->input_buffer)); - - /* Initialize the screen */ - client->screen = silc_screen_init(); - silc_client_create_main_window(client); - client->screen->input_buffer = client->input_buffer->data; - silc_screen_print_coordinates(client->screen, 0); + silc_schedule_init(&client->io_queue, &client->timeout_queue, + &client->generic_queue, 5000); return TRUE; - - err0: - silc_task_queue_free(client->timeout_queue); - err1: - silc_task_queue_free(client->io_queue); - err2: - return FALSE; } /* Stops the client. This is called to stop the client and thus to stop @@ -256,7 +103,7 @@ void silc_client_stop(SilcClient client) silc_client_protocols_unregister(); - SILC_LOG_DEBUG(("Client client")); + SILC_LOG_DEBUG(("Client stopped")); } /* Runs the client. */ @@ -270,457 +117,60 @@ void silc_client_run(SilcClient client) silc_schedule(); } -/* Creates the main window used in SILC client. This is called always - at the initialization of the client. If user wants to create more - than one windows a new windows are always created by calling - silc_client_add_window. */ +/* Allocates and adds new connection to the client. This adds the allocated + connection to the connection table and returns a pointer to it. A client + can have multiple connections to multiple servers. Every connection must + be added to the client using this function. User data `context' may + be sent as argument. */ -SilcClientWindow silc_client_create_main_window(SilcClient client) +SilcClientConnection silc_client_add_connection(SilcClient client, + void *context) { - SilcClientWindow win; - void *screen; - - SILC_LOG_DEBUG(("Creating main window")); - - assert(client->screen != NULL); - - client->screen->u_stat_line.program_name = silc_name; - client->screen->u_stat_line.program_version = silc_version; - - /* Create windows */ - win = silc_calloc(1, sizeof(*win)); - win->nickname = silc_get_username(); - win->local_id = NULL; - win->local_id_data = NULL; - win->local_id_data_len = 0; - win->remote_host = NULL; - win->remote_port = -1; - win->sock = NULL; - - /* Initialize ID caches */ - win->client_cache = silc_idcache_alloc(0); - win->channel_cache = silc_idcache_alloc(0); - win->server_cache = silc_idcache_alloc(0); - - /* Create the actual screen */ - screen = (void *)silc_screen_create_output_window(client->screen); - silc_screen_create_input_window(client->screen); - silc_screen_init_upper_status_line(client->screen); - silc_screen_init_output_status_line(client->screen); - win->screen = screen; - - client->screen->bottom_line->nickname = win->nickname; - silc_screen_print_bottom_line(client->screen, 0); - - /* Add the window to windows table */ - client->windows = silc_calloc(1, sizeof(*client->windows)); - client->windows[client->windows_count] = win; - client->windows_count = 1; - - /* Automatically becomes the current active window */ - client->current_win = win; - - return win; -} - -/* Allocates and adds new window to the client. This allocates new - physical window and internal window for connection specific data. - All the connection specific data is always saved into a window - since connection is always associated to a active window. */ - -SilcClientWindow silc_client_add_window(SilcClient client, - int is_current) -{ - SilcClientWindow win; - - assert(client->screen != NULL); - - win = silc_calloc(1, sizeof(*win)); + SilcClientConnection conn; + int i; - /* Add the pointers */ - win->screen = silc_screen_add_output_window(client->screen); - win->sock = NULL; + conn = silc_calloc(1, sizeof(*conn)); /* Initialize ID caches */ - win->client_cache = silc_idcache_alloc(0); - win->channel_cache = silc_idcache_alloc(0); - win->server_cache = silc_idcache_alloc(0); - - /* Add the window to windows table */ - client->windows = silc_realloc(client->windows, sizeof(*client->windows) - * (client->windows_count + 1)); - client->windows[client->windows_count] = win; - client->windows_count++; - - if (is_current == TRUE) - client->current_win = win; - - return win; -} - -/* The main task on SILC client. This processes the key pressings user - has made. */ - -SILC_TASK_CALLBACK(silc_client_process_key_press) -{ - SilcClient client = (SilcClient)context; - int c; - - /* There is data pending in stdin, this gets it directly */ - c = wgetch(client->screen->input_win); - if (silc_client_bad_keys(c)) - return; - - SILC_LOG_DEBUG(("Pressed key: %d", c)); - - switch(c) { - /* - * Special character handling - */ - case KEY_UP: - case KEY_DOWN: - break; - case KEY_RIGHT: - /* Right arrow */ - SILC_LOG_DEBUG(("RIGHT")); - silc_screen_input_cursor_right(client->screen); - break; - case KEY_LEFT: - /* Left arrow */ - SILC_LOG_DEBUG(("LEFT")); - silc_screen_input_cursor_left(client->screen); - break; - case KEY_BACKSPACE: - case KEY_DC: - case '\177': - case '\b': - /* Backspace */ - silc_screen_input_backspace(client->screen); - break; - case '\011': - /* Tabulator */ - break; - case KEY_IC: - /* Insert switch. Turns on/off insert on input window */ - silc_screen_input_insert(client->screen); - break; - case CTRL('j'): - case '\r': - /* Enter, Return. User pressed enter we are ready to - process the message. */ - silc_client_process_message(client); - break; - case CTRL('l'): - /* Refresh screen, Ctrl^l */ - silc_screen_refresh_all(client->screen); - break; - case CTRL('a'): - case KEY_HOME: - case KEY_BEG: - /* Beginning, Home */ - silc_screen_input_cursor_home(client->screen); - break; - case CTRL('e'): - case KEY_END: - /* End */ - silc_screen_input_cursor_end(client->screen); - break; - case KEY_LL: - /* End */ - break; - case CTRL('g'): - /* Bell, Ctrl^g */ - beep(); - break; - case KEY_DL: - case CTRL('u'): - /* Delete line */ - silc_client_clear_input(client); - break; - default: - /* - * Other characters - */ - if (c < 32) { - /* Control codes are printed as reversed */ - c = (c & 127) | 64; - wattron(client->screen->input_win, A_REVERSE); - silc_screen_input_print(client->screen, c); - wattroff(client->screen->input_win, A_REVERSE); - } else { - /* Normal character */ - silc_screen_input_print(client->screen, c); - } - } - - silc_screen_print_coordinates(client->screen, 0); - silc_screen_refresh_win(client->screen->input_win); -} - -static int silc_client_bad_keys(unsigned char key) -{ - /* these are explained in curses.h */ - switch(key) { - case KEY_SF: - case KEY_SR: - case KEY_NPAGE: - case KEY_PPAGE: - case KEY_PRINT: - case KEY_A1: - case KEY_A3: - case KEY_B2: - case KEY_C1: - case KEY_C3: - case KEY_UNDO: - case KEY_EXIT: - case '\v': /* VT */ - case '\E': /* we ignore ESC */ - return TRUE; - default: - return FALSE; - } -} - -/* Clears input buffer */ - -static void silc_client_clear_input(SilcClient client) -{ - silc_buffer_clear(client->input_buffer); - silc_buffer_pull_tail(client->input_buffer, - SILC_BUFFER_END(client->input_buffer)); - silc_screen_input_reset(client->screen); -} - -/* Processes messages user has typed on the screen. This either sends - a packet out to network or if command were written executes it. */ - -static void silc_client_process_message(SilcClient client) -{ - unsigned char *data; - unsigned int len; - - SILC_LOG_DEBUG(("Start")); - - data = client->input_buffer->data; - len = strlen(data); - - if (data[0] == '/' && data[1] != ' ') { - /* Command */ - unsigned int argc = 0; - unsigned char **argv, *tmpcmd; - unsigned int *argv_lens, *argv_types; - SilcClientCommand *cmd; - SilcClientCommandContext ctx; - - /* Get the command */ - tmpcmd = silc_client_parse_command(data); - - /* Find command match */ - for (cmd = silc_command_list; cmd->name; cmd++) { - if (!strncmp(cmd->name, tmpcmd, strlen(tmpcmd))) - break; + conn->client_cache = silc_idcache_alloc(0); + conn->channel_cache = silc_idcache_alloc(0); + conn->server_cache = silc_idcache_alloc(0); + conn->client = client; + conn->context = context; + + /* Add the connection to connections table */ + for (i = 0; i < client->conns_count; i++) + if (client->conns && !client->conns[i]) { + client->conns[i] = conn; + return conn; } - if (cmd->name == NULL) { - silc_say(client, "Invalid command: %s", tmpcmd); - silc_free(tmpcmd); - goto out; - } - - /* Now parse all arguments */ - silc_client_parse_command_line(data, &argv, &argv_lens, - &argv_types, &argc, cmd->max_args); - silc_free(tmpcmd); - - SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name)); - - /* Allocate command context. This and its internals must be free'd - by the command routine receiving it. */ - ctx = silc_calloc(1, sizeof(*ctx)); - ctx->client = client; - ctx->sock = client->current_win->sock; - ctx->argc = argc; - ctx->argv = argv; - ctx->argv_lens = argv_lens; - ctx->argv_types = argv_types; - - /* Execute command */ - (*cmd->cb)(ctx); + client->conns = silc_realloc(client->conns, sizeof(*client->conns) + * (client->conns_count + 1)); + client->conns[client->conns_count] = conn; + client->conns_count++; - } else { - /* Normal message to a channel */ - if (len && client->current_win->current_channel && - client->current_win->current_channel->on_channel == TRUE) { - silc_print(client, "> %s", data); - silc_client_packet_send_to_channel(client, - client->current_win->sock, - client->current_win->current_channel, - data, strlen(data), TRUE); - } - } - - out: - /* Clear the input buffer */ - silc_client_clear_input(client); + return conn; } -/* Returns the command fetched from user typed command line */ +/* Removes connection from client. */ -static char *silc_client_parse_command(unsigned char *buffer) +void silc_client_del_connection(SilcClient client, SilcClientConnection conn) { - char *ret; - const char *cp = buffer; - int len; - - len = strcspn(cp, " "); - ret = silc_to_upper((char *)++cp); - ret[len - 1] = 0; - - return ret; -} - -/* Parses user typed command line. At most `max_args' is taken. Rest - of the line will be allocated as the last argument if there are more - than `max_args' arguments in the line. Note that the command name - is counted as one argument and is saved. */ - -void silc_client_parse_command_line(unsigned char *buffer, - unsigned char ***parsed, - unsigned int **parsed_lens, - unsigned int **parsed_types, - unsigned int *parsed_num, - unsigned int max_args) -{ - int i, len = 0; - int argc = 0; - const char *cp = buffer; - - /* Take the '/' away */ - cp++; - - *parsed = silc_calloc(1, sizeof(**parsed)); - *parsed_lens = silc_calloc(1, sizeof(**parsed_lens)); - - /* Get the command first */ - len = strcspn(cp, " "); - (*parsed)[0] = silc_to_upper((char *)cp); - (*parsed_lens)[0] = len; - cp += len + 1; - argc++; - - /* Parse arguments */ - if (strchr(cp, ' ') || strlen(cp) != 0) { - for (i = 1; i < max_args; i++) { - - if (i != max_args - 1) - len = strcspn(cp, " "); - else - len = strlen(cp); - - *parsed = silc_realloc(*parsed, sizeof(**parsed) * (argc + 1)); - *parsed_lens = silc_realloc(*parsed_lens, - sizeof(**parsed_lens) * (argc + 1)); - (*parsed)[argc] = silc_calloc(len + 1, sizeof(char)); - memcpy((*parsed)[argc], cp, len); - (*parsed_lens)[argc] = len; - argc++; - - cp += len; - if (strlen(cp) == 0) - break; - else - cp++; - } - } - - /* Save argument types. Protocol defines all argument types but - this implementation makes sure that they are always in correct - order hence this simple code. */ - *parsed_types = silc_calloc(argc, sizeof(**parsed_types)); - for (i = 0; i < argc; i++) - (*parsed_types)[i] = i; - - *parsed_num = argc; -} - -/* Updates clock on the screen every minute. */ - -SILC_TASK_CALLBACK(silc_client_update_clock) -{ - SilcClient client = (SilcClient)context; - - /* Update the clock on the screen */ - silc_screen_print_clock(client->screen); - - /* Re-register this same task */ - silc_task_register(qptr, 0, silc_client_update_clock, context, - silc_client_time_til_next_min(), 0, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_LOW); - - silc_screen_refresh_win(client->screen->input_win); -} - -/* Runs commands user configured in configuration file. This is - called when initializing client. */ - -SILC_TASK_CALLBACK(silc_client_run_commands) -{ - SilcClient client = (SilcClient)context; - SilcClientConfigSectionCommand *cs; - - SILC_LOG_DEBUG(("Start")); - - cs = client->config->commands; - while(cs) { - unsigned int argc = 0; - unsigned char **argv, *tmpcmd; - unsigned int *argv_lens, *argv_types; - SilcClientCommand *cmd; - SilcClientCommandContext ctx; - - /* Get the command */ - tmpcmd = silc_client_parse_command(cs->command); + int i; - for (cmd = silc_command_list; cmd->name; cmd++) { - if (!strcmp(cmd->name, tmpcmd)) - break; - } - - if (cmd->name == NULL) { - silc_say(client, "Invalid command: %s", tmpcmd); - silc_free(tmpcmd); - continue; + for (i = 0; i < client->conns_count; i++) + if (client->conns[i] == conn) { + silc_free(conn); + client->conns[i] = NULL; } - - /* Now parse all arguments */ - silc_client_parse_command_line(cs->command, &argv, &argv_lens, - &argv_types, &argc, cmd->max_args); - silc_free(tmpcmd); - - SILC_LOG_DEBUG(("Exeuting command: %s", cmd->name)); - - /* Allocate command context. This and its internals must be free'd - by the command routine receiving it. */ - ctx = silc_calloc(1, sizeof(*ctx)); - ctx->client = client; - ctx->sock = client->current_win->sock; - ctx->argc = argc; - ctx->argv = argv; - ctx->argv_lens = argv_lens; - ctx->argv_types = argv_types; - - /* Execute command */ - (*cmd->cb)(ctx); - - cs = cs->next; - } } /* Internal context for connection process. This is needed as we doing asynchronous connecting. */ typedef struct { SilcClient client; + SilcClientConnection conn; SilcTask task; int sock; char *host; @@ -755,25 +205,32 @@ silc_client_connect_to_server_internal(SilcClientInternalConnectContext *ctx) return sock; } -/* Connects to remote server */ +/* Connects to remote server. This is the main routine used to connect + to SILC server. Returns -1 on error and the created socket otherwise. + The `context' is user context that is saved into the SilcClientConnection + that is created after the connection is created. */ int silc_client_connect_to_server(SilcClient client, int port, - char *host) + char *host, void *context) { SilcClientInternalConnectContext *ctx; + SilcClientConnection conn; SILC_LOG_DEBUG(("Connecting to port %d of server %s", port, host)); - silc_say(client, "Connecting to port %d of server %s", port, host); + conn = silc_client_add_connection(client, context); + conn->remote_host = strdup(host); + conn->remote_port = port; - client->current_win->remote_host = strdup(host); - client->current_win->remote_port = port; + client->ops->say(client, conn, + "Connecting to port %d of server %s", port, host); /* Allocate internal context for connection process. This is needed as we are doing async connecting. */ ctx = silc_calloc(1, sizeof(*ctx)); ctx->client = client; + ctx->conn = conn; ctx->host = strdup(host); ctx->port = port; ctx->tries = 0; @@ -790,6 +247,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start) SilcClientInternalConnectContext *ctx = (SilcClientInternalConnectContext *)context; SilcClient client = ctx->client; + SilcClientConnection conn = ctx->conn; SilcProtocol protocol; SilcClientKEInternalContext *proto_ctx; int opt, opt_len = sizeof(opt); @@ -801,10 +259,11 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start) if (opt != 0) { if (ctx->tries < 2) { /* Connection failed but lets try again */ - silc_say(ctx->client, "Could not connect to server %s: %s", - ctx->host, strerror(opt)); - silc_say(client, "Connecting to port %d of server %s resumed", - ctx->port, ctx->host); + client->ops->say(client, conn, "Could not connect to server %s: %s", + ctx->host, strerror(opt)); + client->ops->say(client, conn, + "Connecting to port %d of server %s resumed", + ctx->port, ctx->host); /* Unregister old connection try */ silc_schedule_unset_listen_fd(fd); @@ -816,12 +275,15 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start) ctx->tries++; } else { /* Connection failed and we won't try anymore */ - silc_say(ctx->client, "Could not connect to server %s: %s", - ctx->host, strerror(opt)); + client->ops->say(client, conn, "Could not connect to server %s: %s", + ctx->host, strerror(opt)); silc_schedule_unset_listen_fd(fd); silc_net_close_connection(fd); silc_task_unregister(client->io_queue, ctx->task); silc_free(ctx); + + /* Notify application of failure */ + client->ops->connect(client, conn, FALSE); } return; } @@ -831,22 +293,24 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start) silc_free(ctx); /* Allocate new socket connection object */ - silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, - (void *)client->current_win, - &client->current_win->sock); - if (client->current_win->sock == NULL) { - silc_say(client, "Error: Could not allocate connection socket"); + silc_socket_alloc(fd, SILC_SOCKET_TYPE_SERVER, (void *)conn, &conn->sock); + if (conn->sock == NULL) { + client->ops->say(client, conn, + "Error: Could not allocate connection socket"); silc_net_close_connection(fd); + client->ops->connect(client, conn, FALSE); return; } - client->current_win->sock->hostname = client->current_win->remote_host; - client->current_win->sock->port = client->current_win->remote_port; + + conn->nickname = strdup(client->username); + conn->sock->hostname = conn->remote_host; + conn->sock->port = conn->remote_port; /* Allocate internal Key Exchange context. This is sent to the protocol as context. */ proto_ctx = silc_calloc(1, sizeof(*proto_ctx)); proto_ctx->client = (void *)client; - proto_ctx->sock = client->current_win->sock; + proto_ctx->sock = conn->sock; proto_ctx->rng = client->rng; proto_ctx->responder = FALSE; @@ -856,10 +320,12 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_start) &protocol, (void *)proto_ctx, silc_client_connect_to_server_second); if (!protocol) { - silc_say(client, "Error: Could not start authentication protocol"); + client->ops->say(client, conn, + "Error: Could not start authentication protocol"); + client->ops->connect(client, conn, FALSE); return; } - client->current_win->sock->protocol = protocol; + conn->sock->protocol = protocol; /* Register the connection for network input and output. This sets that scheduler will listen for incoming packets for this connection @@ -898,6 +364,9 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second) silc_free(ctx->dest_id); ctx->sock->protocol = NULL; silc_free(ctx); + + /* Notify application of failure */ + client->ops->connect(client, ctx->sock->user_data, FALSE); return; } @@ -911,29 +380,14 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_second) proto_ctx->dest_id = ctx->dest_id; /* Resolve the authentication method to be used in this connection */ - proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE; - if (client->config->conns) { - SilcClientConfigSectionConnection *conn = NULL; - - /* Check if we find a match from user configured connections */ - conn = silc_client_config_find_connection(client->config, - sock->hostname, - sock->port); - if (conn) { - /* Match found. Use the configured authentication method */ - proto_ctx->auth_meth = conn->auth_meth; - if (conn->auth_data) { - proto_ctx->auth_data = strdup(conn->auth_data); - proto_ctx->auth_data_len = strlen(conn->auth_data); - } - } else { - /* No match found. Resolve by sending AUTH_REQUEST to server */ + if (!client->ops->get_auth_method(client, sock->user_data, sock->hostname, + sock->port, &proto_ctx->auth_meth, + &proto_ctx->auth_data, + &proto_ctx->auth_data_len)) + { + /* XXX do AUTH_REQUEST resolcing with server */ proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE; } - } else { - /* XXX Resolve by sending AUTH_REQUEST to server */ - proto_ctx->auth_meth = SILC_PROTOCOL_CONN_AUTH_NONE; - } /* Free old protocol as it is finished now */ silc_protocol_free(protocol); @@ -966,7 +420,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) SilcClientConnAuthInternalContext *ctx = (SilcClientConnAuthInternalContext *)protocol->context; SilcClient client = (SilcClient)ctx->client; - SilcClientWindow win = (SilcClientWindow)ctx->sock->user_data; + SilcClientConnection conn = (SilcClientConnection)ctx->sock->user_data; SilcBuffer packet; SILC_LOG_DEBUG(("Start")); @@ -982,7 +436,10 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) if (ctx->dest_id) silc_free(ctx->dest_id); silc_free(ctx); - win->sock->protocol = NULL; + conn->sock->protocol = NULL; + + /* Notify application of failure */ + client->ops->connect(client, ctx->sock->user_data, FALSE); return; } @@ -1008,15 +465,15 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) silc_buffer_free(packet); /* Save remote ID. */ - win->remote_id = ctx->dest_id; - win->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_CHANNEL); - win->remote_id_data_len = SILC_ID_CHANNEL_LEN; + conn->remote_id = ctx->dest_id; + conn->remote_id_data = silc_id_id2str(ctx->dest_id, SILC_ID_SERVER); + conn->remote_id_data_len = SILC_ID_SERVER_LEN; - silc_say(client, "Connected to port %d of host %s", - win->remote_port, win->remote_host); + client->ops->say(client, conn, "Connected to port %d of host %s", + conn->remote_port, conn->remote_host); - client->screen->bottom_line->connection = win->remote_host; - silc_screen_print_bottom_line(client->screen, 0); + /* Notify application of successful connection */ + client->ops->connect(client, conn, TRUE); silc_protocol_free(protocol); if (ctx->auth_data) @@ -1026,7 +483,7 @@ SILC_TASK_CALLBACK(silc_client_connect_to_server_final) if (ctx->dest_id) silc_free(ctx->dest_id); silc_free(ctx); - win->sock->protocol = NULL; + conn->sock->protocol = NULL; } /* Internal routine that sends packet or marks packet to be sent. This @@ -1065,7 +522,7 @@ SILC_TASK_CALLBACK(silc_client_packet_process) { SilcClient client = (SilcClient)context; SilcSocketConnection sock = NULL; - SilcClientWindow win; + SilcClientConnection conn; int ret; SILC_LOG_DEBUG(("Processing packet")); @@ -1074,7 +531,7 @@ SILC_TASK_CALLBACK(silc_client_packet_process) if (sock == NULL) return; - win = (SilcClientWindow)sock->user_data; + conn = (SilcClientConnection)sock->user_data; /* Packet sending */ if (type == SILC_TASK_WRITE) { @@ -1119,19 +576,20 @@ SILC_TASK_CALLBACK(silc_client_packet_process) close the connection */ if (SILC_IS_DISCONNECTING(sock)) { silc_client_close_connection(client, sock); + client->ops->disconnect(client, conn); return; } - silc_say(client, "Connection closed: premature EOF"); + client->ops->say(client, conn, "Connection closed: premature EOF"); SILC_LOG_DEBUG(("Premature EOF from connection %d", sock->sock)); - silc_client_close_connection(client, sock); + client->ops->disconnect(client, conn); return; } /* Process the packet. This will call the parser that will then decrypt and parse the packet. */ - if (!silc_packet_receive_process(sock, win->receive_key, win->hmac, + if (!silc_packet_receive_process(sock, conn->receive_key, conn->hmac, silc_client_packet_parse, client)) { silc_buffer_clear(sock->inbuf); return; @@ -1148,13 +606,13 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real) SilcPacketContext *packet = parse_ctx->packet; SilcBuffer buffer = packet->buffer; SilcSocketConnection sock = parse_ctx->sock; - SilcClientWindow win = (SilcClientWindow)sock->user_data; + SilcClientConnection conn = (SilcClientConnection)sock->user_data; int ret; SILC_LOG_DEBUG(("Start")); /* Decrypt the received packet */ - ret = silc_packet_decrypt(win->receive_key, win->hmac, buffer, packet); + ret = silc_packet_decrypt(conn->receive_key, conn->hmac, buffer, packet); if (ret < 0) goto out; @@ -1185,27 +643,13 @@ SILC_TASK_CALLBACK(silc_client_packet_parse_real) void silc_client_packet_parse(SilcPacketParserContext *parser_context) { SilcClient client = (SilcClient)parser_context->context; - SilcClientWindow win = (SilcClientWindow)parser_context->sock->user_data; - - /* If this packet is for the current active connection we will - parse the packet right away to get it quickly on the screen. - Otherwise, it will be parsed with a timeout as the data is - for inactive window (which might not be visible at all). */ - if (SILC_CLIENT_IS_CURRENT_WIN(client, win)) { - /* Parse it real soon */ - silc_task_register(client->timeout_queue, parser_context->sock->sock, - silc_client_packet_parse_real, - (void *)parser_context, 0, 1, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_NORMAL); - } else { - /* Parse the packet with timeout */ - silc_task_register(client->timeout_queue, parser_context->sock->sock, - silc_client_packet_parse_real, - (void *)parser_context, 0, 200000, - SILC_TASK_TIMEOUT, - SILC_TASK_PRI_NORMAL); - } + + /* Parse the packet */ + silc_task_register(client->timeout_queue, parser_context->sock->sock, + silc_client_packet_parse_real, + (void *)parser_context, 0, 1, + SILC_TASK_TIMEOUT, + SILC_TASK_PRI_NORMAL); } /* Parses the packet type and calls what ever routines the packet type @@ -1284,14 +728,7 @@ void silc_client_packet_parse_type(SilcClient client, /* * Received private message */ - { - SilcClientCommandReplyContext ctx; - ctx = silc_calloc(1, sizeof(*ctx)); - ctx->client = client; - ctx->sock = sock; - ctx->packet = packet; - silc_client_command_reply_msg((void *)ctx); - } + silc_client_private_message(client, sock, packet); break; case SILC_PACKET_PRIVATE_MESSAGE_KEY: /* @@ -1408,14 +845,14 @@ void silc_client_packet_send(SilcClient client, /* Get data used in the packet sending, keys and stuff */ if ((!cipher || !hmac || !dst_id) && sock->user_data) { - if (!cipher && ((SilcClientWindow)sock->user_data)->send_key) - cipher = ((SilcClientWindow)sock->user_data)->send_key; + if (!cipher && ((SilcClientConnection)sock->user_data)->send_key) + cipher = ((SilcClientConnection)sock->user_data)->send_key; - if (!hmac && ((SilcClientWindow)sock->user_data)->hmac) - hmac = ((SilcClientWindow)sock->user_data)->hmac; + if (!hmac && ((SilcClientConnection)sock->user_data)->hmac) + hmac = ((SilcClientConnection)sock->user_data)->hmac; - if (!dst_id && ((SilcClientWindow)sock->user_data)->remote_id) { - dst_id = ((SilcClientWindow)sock->user_data)->remote_id; + if (!dst_id && ((SilcClientConnection)sock->user_data)->remote_id) { + dst_id = ((SilcClientConnection)sock->user_data)->remote_id; dst_id_type = SILC_ID_SERVER; } } @@ -1423,8 +860,8 @@ void silc_client_packet_send(SilcClient client, /* Set the packet context pointers */ packetdata.flags = 0; packetdata.type = type; - if (((SilcClientWindow)sock->user_data)->local_id_data) - packetdata.src_id = ((SilcClientWindow)sock->user_data)->local_id_data; + if (((SilcClientConnection)sock->user_data)->local_id_data) + packetdata.src_id = ((SilcClientConnection)sock->user_data)->local_id_data; else packetdata.src_id = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char)); packetdata.src_id_len = SILC_ID_CLIENT_LEN; @@ -1487,7 +924,7 @@ void silc_client_packet_send_to_channel(SilcClient client, int force_send) { int i; - SilcClientWindow win = (SilcClientWindow)sock->user_data; + SilcClientConnection conn = (SilcClientConnection)sock->user_data; SilcBuffer payload; SilcPacketContext packetdata; SilcCipher cipher; @@ -1497,7 +934,8 @@ void silc_client_packet_send_to_channel(SilcClient client, SILC_LOG_DEBUG(("Sending packet to channel")); if (!channel || !channel->key) { - silc_say(client, "Cannot talk to channel: key does not exist"); + client->ops->say(client, conn, + "Cannot talk to channel: key does not exist"); return; } @@ -1509,20 +947,20 @@ void silc_client_packet_send_to_channel(SilcClient client, silc_hash_make(client->md5hash, channel->iv, 16, channel->iv); /* Encode the channel payload */ - payload = silc_channel_encode_payload(strlen(win->nickname), win->nickname, + payload = silc_channel_encode_payload(strlen(conn->nickname), conn->nickname, data_len, data, 16, channel->iv, client->rng); if (!payload) { - silc_say(client, - "Error: Could not create packet to be sent to the channel"); + client->ops->say(client, conn, + "Error: Could not create packet to be sent to channel"); return; } /* Get data used in packet header encryption, keys and stuff. Rest of the packet (the payload) is, however, encrypted with the specified channel key. */ - cipher = win->send_key; - hmac = win->hmac; + cipher = conn->send_key; + hmac = conn->hmac; id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL); /* Set the packet context pointers. The destination ID is always @@ -1530,7 +968,7 @@ void silc_client_packet_send_to_channel(SilcClient client, distribution of the packet. */ packetdata.flags = 0; packetdata.type = SILC_PACKET_CHANNEL_MESSAGE; - packetdata.src_id = win->local_id_data; + packetdata.src_id = conn->local_id_data; packetdata.src_id_len = SILC_ID_CLIENT_LEN; packetdata.src_id_type = SILC_ID_CLIENT; packetdata.dst_id = id_string; @@ -1594,7 +1032,7 @@ void silc_client_packet_send_private_message(SilcClient client, unsigned int data_len, int force_send) { - SilcClientWindow win = (SilcClientWindow)sock->user_data; + SilcClientConnection conn = (SilcClientConnection)sock->user_data; SilcBuffer buffer; SilcPacketContext packetdata; unsigned int nick_len; @@ -1604,12 +1042,12 @@ void silc_client_packet_send_private_message(SilcClient client, SILC_LOG_DEBUG(("Sending private message")); /* Create private message payload */ - nick_len = strlen(client->current_win->nickname); + nick_len = strlen(conn->nickname); buffer = silc_buffer_alloc(2 + nick_len + data_len); silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer)); silc_buffer_format(buffer, SILC_STR_UI_SHORT(nick_len), - SILC_STR_UI_XNSTRING(client->current_win->nickname, + SILC_STR_UI_XNSTRING(conn->nickname, nick_len), SILC_STR_UI_XNSTRING(data, data_len), SILC_STR_END); @@ -1629,18 +1067,18 @@ void silc_client_packet_send_private_message(SilcClient client, /* Get data used in the encryption */ cipher = client_entry->send_key; - hmac = win->hmac; + hmac = conn->hmac; /* Set the packet context pointers. */ packetdata.flags = 0; packetdata.type = SILC_PACKET_PRIVATE_MESSAGE; - packetdata.src_id = win->local_id_data; + packetdata.src_id = conn->local_id_data; packetdata.src_id_len = SILC_ID_CLIENT_LEN; packetdata.src_id_type = SILC_ID_CLIENT; if (client_entry) packetdata.dst_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT); else - packetdata.dst_id = win->local_id_data; + packetdata.dst_id = conn->local_id_data; packetdata.dst_id_len = SILC_ID_CLIENT_LEN; packetdata.dst_id_type = SILC_ID_CLIENT; packetdata.rng = client->rng; @@ -1693,7 +1131,7 @@ void silc_client_packet_send_private_message(SilcClient client, void silc_client_close_connection(SilcClient client, SilcSocketConnection sock) { - SilcClientWindow win; + SilcClientConnection conn; /* We won't listen for this connection anymore */ silc_schedule_unset_listen_fd(sock->sock); @@ -1705,49 +1143,50 @@ void silc_client_close_connection(SilcClient client, /* Close the actual connection */ silc_net_close_connection(sock->sock); - silc_say(client, "Closed connection to host %s", sock->hostname ? - sock->hostname : sock->ip); + client->ops->say(client, sock->user_data, + "Closed connection to host %s", sock->hostname ? + sock->hostname : sock->ip); /* Free everything */ if (sock->user_data) { - win = (SilcClientWindow)sock->user_data; + conn = (SilcClientConnection)sock->user_data; /* XXX Free all client entries and channel entries. */ /* Clear ID caches */ - silc_idcache_del_all(win->client_cache); - silc_idcache_del_all(win->channel_cache); + silc_idcache_del_all(conn->client_cache); + silc_idcache_del_all(conn->channel_cache); /* Free data */ - if (win->remote_host) - silc_free(win->remote_host); - if (win->local_id) - silc_free(win->local_id); - if (win->local_id_data) - silc_free(win->local_id_data); - if (win->send_key) - silc_cipher_free(win->send_key); - if (win->receive_key) - silc_cipher_free(win->receive_key); - if (win->hmac) - silc_hmac_free(win->hmac); - if (win->hmac_key) { - memset(win->hmac_key, 0, win->hmac_key_len); - silc_free(win->hmac_key); + if (conn->remote_host) + silc_free(conn->remote_host); + if (conn->local_id) + silc_free(conn->local_id); + if (conn->local_id_data) + silc_free(conn->local_id_data); + if (conn->send_key) + silc_cipher_free(conn->send_key); + if (conn->receive_key) + silc_cipher_free(conn->receive_key); + if (conn->hmac) + silc_hmac_free(conn->hmac); + if (conn->hmac_key) { + memset(conn->hmac_key, 0, conn->hmac_key_len); + silc_free(conn->hmac_key); } - win->sock = NULL; - win->remote_port = 0; - win->remote_type = 0; - win->send_key = NULL; - win->receive_key = NULL; - win->hmac = NULL; - win->hmac_key = NULL; - win->hmac_key_len = 0; - win->local_id = NULL; - win->local_id_data = NULL; - win->remote_host = NULL; - win->current_channel = NULL; + conn->sock = NULL; + conn->remote_port = 0; + conn->remote_type = 0; + conn->send_key = NULL; + conn->receive_key = NULL; + conn->hmac = NULL; + conn->hmac_key = NULL; + conn->hmac_key_len = 0; + conn->local_id = NULL; + conn->local_id_data = NULL; + conn->remote_host = NULL; + conn->current_channel = NULL; } if (sock->protocol) { @@ -1771,7 +1210,7 @@ void silc_client_disconnected_by_server(SilcClient client, msg = silc_calloc(message->len + 1, sizeof(char)); memcpy(msg, message->data, message->len); - silc_say(client, msg); + client->ops->say(client, sock->user_data, msg); silc_free(msg); SILC_SET_DISCONNECTED(sock); @@ -1789,7 +1228,7 @@ void silc_client_error_by_server(SilcClient client, msg = silc_calloc(message->len + 1, sizeof(char)); memcpy(msg, message->data, message->len); - silc_say(client, msg); + client->ops->say(client, sock->user_data, msg); silc_free(msg); } @@ -1803,7 +1242,7 @@ void silc_client_notify_by_server(SilcClient client, msg = silc_calloc(message->len + 1, sizeof(char)); memcpy(msg, message->data, message->len); - silc_say(client, msg); + client->ops->say(client, sock->user_data, msg); silc_free(msg); } @@ -1814,29 +1253,29 @@ void silc_client_receive_new_id(SilcClient client, SilcSocketConnection sock, unsigned char *id_string) { - SilcClientWindow win = (SilcClientWindow)sock->user_data; + SilcClientConnection conn = (SilcClientConnection)sock->user_data; /* Delete old ID from ID cache */ - silc_idcache_del_by_id(win->client_cache, SILC_ID_CLIENT, win->local_id); + silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT, conn->local_id); /* Save the new ID */ - if (win->local_id) - silc_free(win->local_id); - win->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT); - if (win->local_id_data) - silc_free(win->local_id_data); - win->local_id_data = + if (conn->local_id) + silc_free(conn->local_id); + conn->local_id = silc_id_str2id(id_string, SILC_ID_CLIENT); + if (conn->local_id_data) + silc_free(conn->local_id_data); + conn->local_id_data = silc_calloc(SILC_ID_CLIENT_LEN, sizeof(unsigned char)); - memcpy(win->local_id_data, id_string, SILC_ID_CLIENT_LEN); - win->local_id_data_len = SILC_ID_CLIENT_LEN; - if (!win->local_entry) - win->local_entry = silc_calloc(1, sizeof(*win->local_entry)); - win->local_entry->nickname = win->nickname; - win->local_entry->id = win->local_id; + memcpy(conn->local_id_data, id_string, SILC_ID_CLIENT_LEN); + conn->local_id_data_len = SILC_ID_CLIENT_LEN; + if (!conn->local_entry) + conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry)); + conn->local_entry->nickname = conn->nickname; + conn->local_entry->id = conn->local_id; /* Put it to the ID cache */ - silc_idcache_add(win->client_cache, win->nickname, SILC_ID_CLIENT, - win->local_id, (void *)win->local_entry, TRUE); + silc_idcache_add(conn->client_cache, conn->nickname, SILC_ID_CLIENT, + conn->local_id, (void *)conn->local_entry, TRUE); } /* Processed received Channel ID for a channel. This is called when client @@ -1848,7 +1287,7 @@ void silc_client_new_channel_id(SilcClient client, unsigned int mode, unsigned char *id_string) { - SilcClientWindow win = (SilcClientWindow)sock->user_data; + SilcClientConnection conn = (SilcClientConnection)sock->user_data; SilcChannelID *id; SilcChannelEntry channel; @@ -1859,10 +1298,10 @@ void silc_client_new_channel_id(SilcClient client, channel->channel_name = channel_name; channel->id = id; channel->mode = mode; - win->current_channel = channel; + conn->current_channel = channel; /* Put it to the ID cache */ - silc_idcache_add(win->channel_cache, channel_name, SILC_ID_CHANNEL, + silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL, (void *)id, (void *)channel, TRUE); } @@ -1878,7 +1317,7 @@ void silc_client_receive_channel_key(SilcClient client, { unsigned char *id_string, *key, *cipher; unsigned int key_len; - SilcClientWindow win = (SilcClientWindow)sock->user_data; + SilcClientConnection conn = (SilcClientConnection)sock->user_data; SilcChannelID *id; SilcIDCacheEntry id_cache = NULL; SilcChannelEntry channel; @@ -1898,7 +1337,7 @@ void silc_client_receive_channel_key(SilcClient client, id = silc_id_str2id(id_string, SILC_ID_CHANNEL); /* Find channel. */ - if (!silc_idcache_find_by_id_one(win->channel_cache, (void *)id, + if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id, SILC_ID_CHANNEL, &id_cache)) goto out; @@ -1913,7 +1352,8 @@ void silc_client_receive_channel_key(SilcClient client, silc_cipher_alloc(cipher, &channel->channel_key); if (!channel->channel_key) { - silc_say(client, "Cannot talk to channel: unsupported cipher %s", cipher); + client->ops->say(client, conn, + "Cannot talk to channel: unsupported cipher %s", cipher); goto out; } channel->channel_key->cipher->set_key(channel->channel_key->context, @@ -1935,7 +1375,7 @@ void silc_client_channel_message(SilcClient client, SilcSocketConnection sock, SilcPacketContext *packet) { - SilcClientWindow win = (SilcClientWindow)sock->user_data; + SilcClientConnection conn = (SilcClientConnection)sock->user_data; SilcBuffer buffer = packet->buffer; SilcChannelPayload payload = NULL; SilcChannelID *id = NULL; @@ -1949,7 +1389,7 @@ void silc_client_channel_message(SilcClient client, id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL); /* Find the channel entry from channels on this window */ - if (!silc_idcache_find_by_id_one(win->channel_cache, (void *)id, + if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id, SILC_ID_CHANNEL, &id_cache)) goto out; @@ -1968,21 +1408,16 @@ void silc_client_channel_message(SilcClient client, if (!payload) goto out; - /* Display the message on screen */ + /* Pass the message to application */ if (packet->src_id_type == SILC_ID_CLIENT) { - /* Message from client */ - if (channel == win->current_channel) - silc_print(client, "<%s> %s", - silc_channel_get_nickname(payload, NULL), - silc_channel_get_data(payload, NULL)); - else - silc_print(client, "<%s:%s> %s", - silc_channel_get_nickname(payload, NULL), - channel->channel_name, - silc_channel_get_data(payload, NULL)); + client->ops->channel_message(client, conn, + silc_channel_get_nickname(payload, NULL), + channel->channel_name, + silc_channel_get_data(payload, NULL)); } else { /* Message from server */ - silc_say(client, "%s", silc_channel_get_data(payload, NULL)); + /* XXX maybe this should be passed to app... */ + client->ops->say(client, conn, "%s", silc_channel_get_data(payload, NULL)); } out: @@ -1991,3 +1426,74 @@ void silc_client_channel_message(SilcClient client, if (payload) silc_channel_free_payload(payload); } + +/* Private message received. This processes the private message and + finally displays it on the screen. */ + +void silc_client_private_message(SilcClient client, + SilcSocketConnection sock, + SilcPacketContext *packet) +{ + SilcClientConnection conn = (SilcClientConnection)sock->user_data; + SilcBuffer buffer = packet->buffer; + unsigned short nick_len; + unsigned char *nickname, *message; + + /* Get nickname */ + silc_buffer_unformat(buffer, + SILC_STR_UI16_NSTRING_ALLOC(&nickname, &nick_len), + SILC_STR_END); + silc_buffer_pull(buffer, 2 + nick_len); + + message = silc_calloc(buffer->len + 1, sizeof(char)); + memcpy(message, buffer->data, buffer->len); + + /* Pass the private message to application */ + client->ops->private_message(client, conn, nickname, message); + + /* See if we are away (gone). If we are away we will reply to the + sender with the set away message. */ + if (conn->away && conn->away->away) { + SilcClientID *remote_id; + SilcClientEntry remote_client; + SilcIDCacheEntry id_cache; + + if (packet->src_id_type != SILC_ID_CLIENT) + goto out; + + remote_id = silc_id_str2id(packet->src_id, SILC_ID_CLIENT); + if (!remote_id) + goto out; + + if (!SILC_ID_CLIENT_COMPARE(remote_id, conn->local_id)) + goto out; + + /* Check whether we know this client already */ + if (!silc_idcache_find_by_id_one(conn->client_cache, remote_id, + SILC_ID_CLIENT, &id_cache)) + { + /* Allocate client entry */ + remote_client = silc_calloc(1, sizeof(*remote_client)); + remote_client->id = remote_id; + remote_client->nickname = strdup(nickname); + + /* Save the client to cache */ + silc_idcache_add(conn->client_cache, remote_client->nickname, + SILC_ID_CLIENT, remote_client->id, remote_client, + TRUE); + } else { + silc_free(remote_id); + remote_client = (SilcClientEntry)id_cache->context; + } + + /* Send the away message */ + silc_client_packet_send_private_message(client, sock, remote_client, + conn->away->away, + strlen(conn->away->away), TRUE); + } + + out: + memset(message, 0, buffer->len); + silc_free(message); + silc_free(nickname); +}