+++ /dev/null
-/*
-
- silc.c
-
- Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
-
- Copyright (C) 1997 - 2000 Pekka Riikonen
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
-*/
-/* $Id$ */
-
-#include "clientincludes.h"
-#include "version.h"
-
-/* Static function prototypes */
-static int silc_client_bad_keys(unsigned char key);
-static void silc_client_clear_input(SilcClientInternal app);
-static void silc_client_process_message(SilcClientInternal app);
-static char *silc_client_parse_command(unsigned char *buffer);
-
-void silc_client_create_main_window(SilcClientInternal app);
-
-/* 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);
-
-/* Long command line options */
-static struct option long_opts[] =
-{
- /* Generic options */
- { "server", 1, NULL, 's' },
- { "port", 1, NULL, 'p' },
- { "nickname", 1, NULL, 'n' },
- { "channel", 1, NULL, 'c' },
- { "cipher", 1, NULL, 'r' },
- { "public-key", 1, NULL, 'b' },
- { "private-key", 1, NULL, 'k' },
- { "config-file", 1, NULL, 'f' },
- { "no-silcrc", 0, NULL, 'q' },
- { "debug", 0, NULL, 'd' },
- { "help", 0, NULL, 'h' },
- { "version", 0, NULL, 'V' },
- { "list-ciphers", 0, NULL, 1 },
- { "list-hash-funcs", 0, NULL, 2 },
- { "list-pkcs", 0, NULL, 3 },
-
- /* Key management options */
- { "create-key-pair", 0, NULL, 'C' },
- { "pkcs", 1, NULL, 10 },
- { "bits", 1, NULL, 11 },
- { "show-key", 1, NULL, 'S' },
-
- { NULL, 0, NULL, 0 }
-};
-
-/* Command line option variables */
-static char *opt_server = NULL;
-static int opt_port = 0;
-static char *opt_nickname = NULL;
-static char *opt_channel = NULL;
-static char *opt_cipher = NULL;
-static char *opt_public_key = NULL;
-static char *opt_private_key = NULL;
-static char *opt_config_file = NULL;
-static bool opt_no_silcrc = FALSE;
-
-static bool opt_create_keypair = FALSE;
-static bool opt_show_key = FALSE;
-static char *opt_pkcs = NULL;
-static char *opt_keyfile = NULL;
-static int opt_bits = 0;
-
-/* SILC Client operations */
-extern SilcClientOperations ops;
-
-/* Prints out the usage of silc client */
-
-void usage()
-{
- printf("\
-Usage: silc [options]\n\
-\n\
- Generic Options:\n\
- -s, --server=HOST Open connection to server HOST\n\
- -p, --port=PORT Set PORT as default port to connect\n\
- -n, --nickname=STRING Set default nickname on startup\n\
- -c, --channel=STRING Join channel on startup\n\
- -r, --cipher=CIPHER Use CIPHER as default cipher in SILC\n\
- -b, --public-key=FILE Public key used in SILC\n\
- -k, --private-key=FILE Private key used in SILC\n\
- -f, --config-file=FILE Alternate configuration file\n\
- -q, --no-silcrc Don't load ~/.silcrc on startup\n\
- -d, --debug Enable debugging\n\
- -h, --help Display this help message\n\
- -V, --version Display version\n\
- --list-ciphers List supported ciphers\n\
- --list-hash-funcs List supported hash functions\n\
- --list-pkcs List supported PKCS's\n\
-\n\
- Key Management Options:\n\
- -C, --create-key-pair Create new public key pair\n\
- --pkcs=PKCS Set the PKCS of the public key pair\n\
- --bits=VALUE Set length of the public key pair\n\
- -S, --show-key=FILE Show the contents of the public key\n\
-\n");
-}
-
-int main(int argc, char **argv)
-{
- int opt, option_index = 1;
- int ret;
- SilcClient silc = NULL;
- SilcClientInternal app = NULL;
-
- silc_debug = FALSE;
-
- if (argc > 1)
- {
- while ((opt =
- getopt_long(argc, argv,
- "s:p:n:c:b:k:f:qdhVCS:",
- long_opts, &option_index)) != EOF)
- {
- switch(opt)
- {
- /*
- * Generic options
- */
- case 's':
- if (optarg)
- opt_server = strdup(optarg);
- break;
- case 'p':
- if (optarg)
- opt_port = atoi(optarg);
- break;
- case 'n':
- if (optarg)
- opt_nickname = strdup(optarg);
- break;
- case 'c':
- if (optarg)
- opt_channel = strdup(optarg);
- break;
- case 'r':
- if (optarg)
- opt_cipher = strdup(optarg);
- break;
- case 'b':
- if (optarg)
- opt_public_key = strdup(optarg);
- break;
- case 'k':
- if (optarg)
- opt_private_key = strdup(optarg);
- break;
- case 'f':
- if (optarg)
- opt_config_file = strdup(optarg);
- break;
- case 'q':
- opt_no_silcrc = TRUE;
- break;
- case 'd':
- silc_debug = TRUE;
- break;
- case 'h':
- usage();
- exit(0);
- break;
- case 'V':
- printf("\
-SILC Secure Internet Live Conferencing, version %s\n",
- silc_version);
- printf("\
-(c) 1997 - 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>\n");
- exit(0);
- break;
- case 1:
- silc_client_list_ciphers();
- exit(0);
- break;
- case 2:
- silc_client_list_hash_funcs();
- exit(0);
- break;
- case 3:
- silc_client_list_pkcs();
- exit(0);
- break;
-
- /*
- * Key management options
- */
- case 'C':
- opt_create_keypair = TRUE;
- break;
- case 10:
- if (optarg)
- opt_pkcs = strdup(optarg);
- break;
- case 11:
- if (optarg)
- opt_bits = atoi(optarg);
- break;
- case 'S':
- opt_show_key = TRUE;
- if (optarg)
- opt_keyfile = strdup(optarg);
- break;
-
- default:
- exit(0);
- break;
- }
- }
- }
-
- /* Init signals */
- signal(SIGHUP, SIG_DFL);
- signal(SIGTERM, SIG_DFL);
- signal(SIGPIPE, SIG_IGN);
- signal(SIGCHLD, SIG_DFL);
- signal(SIGALRM, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGSEGV, SIG_DFL);
- signal(SIGBUS, SIG_DFL);
- signal(SIGFPE, SIG_DFL);
- // signal(SIGINT, SIG_IGN);
-
-#ifdef SOCKS
- /* Init SOCKS */
- SOCKSinit(argv[0]);
-#endif
-
- if (opt_create_keypair == TRUE) {
- /* Create new key pair and exit */
- silc_cipher_register_default();
- silc_pkcs_register_default();
- silc_hash_register_default();
- silc_hmac_register_default();
- silc_client_create_key_pair(opt_pkcs, opt_bits,
- NULL, NULL, NULL, NULL, NULL);
- silc_free(opt_pkcs);
- exit(0);
- }
-
- if (opt_show_key == TRUE) {
- /* Dump the key */
- silc_cipher_register_default();
- silc_pkcs_register_default();
- silc_hash_register_default();
- silc_hmac_register_default();
- silc_client_show_key(opt_keyfile);
- silc_free(opt_keyfile);
- exit(0);
- }
-
- /* Default configuration file */
- if (!opt_config_file)
- opt_config_file = strdup(SILC_CLIENT_CONFIG_FILE);
-
- /* Allocate internal application context */
- app = silc_calloc(1, sizeof(*app));
-
- /* Allocate new client */
- app->client = silc = silc_client_alloc(&ops, app, silc_version_string);
- if (!silc)
- goto fail;
-
- /* Read global configuration file. */
- app->config = silc_client_config_alloc(opt_config_file);
-
- /* XXX Read local configuration file */
-
- /* Get user information */
- silc->username = silc_get_username();
- silc->hostname = silc_net_localhost();
- silc->realname = silc_get_real_name();
-
- /* Register all configured ciphers, PKCS and hash functions. */
- if (app->config) {
- app->config->client = (void *)app;
- if (!silc_client_config_register_ciphers(app->config))
- silc_cipher_register_default();
- if (!silc_client_config_register_pkcs(app->config))
- silc_pkcs_register_default();
- if (!silc_client_config_register_hashfuncs(app->config))
- silc_hash_register_default();
- if (!silc_client_config_register_hmacs(app->config))
- silc_hmac_register_default();
- } else {
- /* Register default ciphers, pkcs, hash funtions and hmacs. */
- silc_cipher_register_default();
- silc_pkcs_register_default();
- silc_hash_register_default();
- silc_hmac_register_default();
- }
-
- /* Check ~/.silc directory and public and private keys */
- if (silc_client_check_silc_dir() == FALSE)
- goto fail;
-
- /* Load public and private key */
- if (silc_client_load_keys(silc) == FALSE)
- goto fail;
-
- /* Initialize the client. This initializes the client library and
- sets everything ready for silc_client_run. */
- ret = silc_client_init(silc);
- if (ret == FALSE)
- goto fail;
-
- /* Register the main task that is used in client. This receives
- the key pressings. */
- silc_task_register(silc->io_queue, fileno(stdin),
- silc_client_process_key_press,
- (void *)silc, 0, 0,
- SILC_TASK_FD,
- SILC_TASK_PRI_NORMAL);
-
- /* Register timeout task that updates clock every minute. */
- silc_task_register(silc->timeout_queue, 0,
- silc_client_update_clock,
- (void *)silc,
- silc_client_time_til_next_min(), 0,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
-
- if (app->config && app->config->commands) {
- /* Run user configured commands with timeout */
- silc_task_register(silc->timeout_queue, 0,
- silc_client_run_commands,
- (void *)silc, 0, 1,
- SILC_TASK_TIMEOUT,
- SILC_TASK_PRI_LOW);
- }
-
- /* Allocate the input buffer used to save typed characters */
- app->input_buffer = silc_buffer_alloc(SILC_SCREEN_INPUT_WIN_SIZE);
- silc_buffer_pull_tail(app->input_buffer,
- SILC_BUFFER_END(app->input_buffer));
-
- /* Initialize the screen */
- silc_client_create_main_window(app);
- silc_screen_print_coordinates(app->screen, 0);
-
- /* Run the client. When this returns the application will be
- terminated. */
- silc_client_run(silc);
-
- /* Stop the client. This probably has been done already but it
- doesn't hurt to do it here again. */
- silc_client_stop(silc);
- silc_client_free(silc);
-
- exit(0);
-
- fail:
- if (opt_config_file)
- silc_free(opt_config_file);
- if (app->config)
- silc_client_config_free(app->config);
- if (silc)
- silc_client_free(silc);
- exit(1);
-}
-
-/* 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. */
-
-void silc_client_create_main_window(SilcClientInternal app)
-{
- void *screen;
-
- SILC_LOG_DEBUG(("Creating main window"));
-
- app->screen = silc_screen_init();
- app->screen->input_buffer = app->input_buffer->data;
- app->screen->u_stat_line.program_name = silc_name;
- app->screen->u_stat_line.program_version = silc_version;
-
- /* Create the actual screen */
- screen = (void *)silc_screen_create_output_window(app->screen);
- silc_screen_create_input_window(app->screen);
- silc_screen_init_upper_status_line(app->screen);
- silc_screen_init_output_status_line(app->screen);
-
- app->screen->bottom_line->nickname = silc_get_username();
- silc_screen_print_bottom_line(app->screen, 0);
-}
-
-/* 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;
- SilcClientInternal app = (SilcClientInternal)client->application;
- int c;
-
- /* There is data pending in stdin, this gets it directly */
- c = wgetch(app->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(app->screen);
- break;
- case KEY_LEFT:
- /* Left arrow */
- SILC_LOG_DEBUG(("LEFT"));
- silc_screen_input_cursor_left(app->screen);
- break;
- case KEY_BACKSPACE:
- case KEY_DC:
- case '\177':
- case '\b':
- /* Backspace */
- silc_screen_input_backspace(app->screen);
- break;
- case '\011':
- /* Tabulator */
- break;
- case KEY_IC:
- /* Insert switch. Turns on/off insert on input window */
- silc_screen_input_insert(app->screen);
- break;
- case CTRL('j'):
- case '\r':
- /* Enter, Return. User pressed enter we are ready to
- process the message. */
- silc_client_process_message(app);
- break;
- case CTRL('l'):
- /* Refresh screen, Ctrl^l */
- silc_screen_refresh_all(app->screen);
- break;
- case CTRL('a'):
- case KEY_HOME:
-#ifdef KEY_BEG
- case KEY_BEG:
-#endif
- /* Beginning, Home */
- silc_screen_input_cursor_home(app->screen);
- break;
- case CTRL('e'):
-#ifdef KEY_END
- case KEY_END:
-#endif
- case KEY_LL:
- /* End */
- silc_screen_input_cursor_end(app->screen);
- break;
- case CTRL('g'):
- /* Bell, Ctrl^g */
- beep();
- break;
- case KEY_DL:
- case CTRL('u'):
- /* Delete line */
- silc_client_clear_input(app);
- break;
- default:
- /*
- * Other characters
- */
- if (c < 32) {
- /* Control codes are printed as reversed */
- c = (c & 127) | 64;
- wattron(app->screen->input_win, A_REVERSE);
- silc_screen_input_print(app->screen, c);
- wattroff(app->screen->input_win, A_REVERSE);
- } else {
- /* Normal character */
- silc_screen_input_print(app->screen, c);
- }
- }
-
- silc_screen_print_coordinates(app->screen, 0);
- silc_screen_refresh_win(app->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:
-#ifdef KEY_UNDO
- case KEY_UNDO:
-#endif
-#ifdef KEY_EXIT
- case KEY_EXIT:
-#endif
- case '\v': /* VT */
- case '\E': /* we ignore ESC */
- return TRUE;
- default:
- return FALSE;
- }
-}
-
-/* Clears input buffer */
-
-static void silc_client_clear_input(SilcClientInternal app)
-{
- silc_buffer_clear(app->input_buffer);
- silc_buffer_pull_tail(app->input_buffer,
- SILC_BUFFER_END(app->input_buffer));
- silc_screen_input_reset(app->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(SilcClientInternal app)
-{
- unsigned char *data;
- SilcUInt32 len;
-
- SILC_LOG_DEBUG(("Start"));
-
- data = app->input_buffer->data;
- len = strlen(data);
-
- if (data[0] == '/' && data[1] != ' ') {
- /* Command */
- SilcUInt32 argc = 0;
- unsigned char **argv, *tmpcmd;
- SilcUInt32 *argv_lens, *argv_types;
- SilcClientCommand *cmd;
- SilcClientCommandContext ctx;
-
- /* Get the command */
- tmpcmd = silc_client_parse_command(data);
- cmd = silc_client_local_command_find(tmpcmd);
- if (!cmd && (cmd = silc_client_command_find(tmpcmd)) == NULL) {
- silc_say(app->client, app->current_win, "Invalid command: %s", tmpcmd);
- silc_free(tmpcmd);
- goto out;
- }
-
- /* Now parse all arguments */
- silc_parse_command_line(data + 1, &argv, &argv_lens,
- &argv_types, &argc, cmd->max_args);
- silc_free(tmpcmd);
-
- SILC_LOG_DEBUG(("Executing command: %s", cmd->name));
-
- /* Allocate command context. This and its internals must be free'd
- by the command routine receiving it. */
- ctx = silc_client_command_alloc();
- ctx->client = app->client;
- ctx->conn = app->conn;
- ctx->command = cmd;
- ctx->argc = argc;
- ctx->argv = argv;
- ctx->argv_lens = argv_lens;
- ctx->argv_types = argv_types;
-
- /* Execute command */
- (*cmd->cb)(ctx);
-
- } else {
- /* Normal message to a channel */
- if (len && app->conn && app->conn->current_channel &&
- app->conn->current_channel->on_channel == TRUE) {
- silc_print(app->client, "> %s", data);
- silc_client_send_channel_message(app->client,
- app->conn,
- app->conn->current_channel, NULL,
- 0, data, strlen(data), TRUE);
- }
- }
-
- out:
- /* Clear the input buffer */
- silc_client_clear_input(app);
-}
-
-/* Returns the command fetched from user typed command line */
-
-static char *silc_client_parse_command(unsigned char *buffer)
-{
- char *ret;
- const char *cp = buffer;
- int len;
-
- len = strcspn(cp, " ");
- ret = silc_to_upper((char *)++cp);
- ret[len - 1] = 0;
-
- return ret;
-}
-
-/* Updates clock on the screen every minute. */
-
-SILC_TASK_CALLBACK(silc_client_update_clock)
-{
- SilcClient client = (SilcClient)context;
- SilcClientInternal app = (SilcClientInternal)client->application;
-
- /* Update the clock on the screen */
- silc_screen_print_clock(app->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(app->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;
- SilcClientInternal app = (SilcClientInternal)client->application;
- SilcClientConfigSectionCommand *cs;
-
- SILC_LOG_DEBUG(("Start"));
-
- cs = app->config->commands;
- while(cs) {
- SilcUInt32 argc = 0;
- unsigned char **argv, *tmpcmd;
- SilcUInt32 *argv_lens, *argv_types;
- SilcClientCommand *cmd;
- SilcClientCommandContext ctx;
-
- /* Get the command */
- tmpcmd = silc_client_parse_command(cs->command);
- cmd = silc_client_local_command_find(tmpcmd);
- if (!cmd && (cmd = silc_client_command_find(tmpcmd)) == NULL) {
- silc_say(client, app->conn, "Invalid command: %s", tmpcmd);
- silc_free(tmpcmd);
- continue;
- }
-
- /* Now parse all arguments */
- silc_parse_command_line(cs->command + 1, &argv, &argv_lens,
- &argv_types, &argc, cmd->max_args);
- silc_free(tmpcmd);
-
- SILC_LOG_DEBUG(("Executing command: %s", cmd->name));
-
- /* Allocate command context. This and its internals must be free'd
- by the command routine receiving it. */
- ctx = silc_client_command_alloc();
- ctx->client = client;
- ctx->conn = app->conn;
- ctx->command = cmd;
- ctx->argc = argc;
- ctx->argv = argv;
- ctx->argv_lens = argv_lens;
- ctx->argv_types = argv_types;
-
- /* Execute command */
- (*cmd->cb)(ctx);
-
- cs = cs->next;
- }
-}