+Tue Oct 31 20:10:37 EET 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
+
+ * Updated README.
+
+ * Added TRQ (efficient deque and list library) into lib/trq. This is
+ a very good list library that is currently used in the SILC. Defined
+ SilcList API over the library because I didn't like the API very
+ much. See lib/trq/silclist.h for the API and examples of how to
+ use the API. Fixed various places in the code to use the new
+ SilcList API. The SilcList is meant for lists that has a structure
+ already defined as a list. It is not suitable to add just some
+ context to the list (in TRQ, the context is the list actually).
+
+ So, I defined SilcDList that can be used for the purpose where
+ predefined list structure does not exit. This can be used as
+ such list. Now some context just can be added to the SilcDList.
+ Currently this list is not used in the SILC just yet, though there
+ are a lot places where this can replace dynamically allocated
+ tables and I will fix these places, later, to use SilcDList.
+ See lib/trq/silcdlist.h for SilcDList (they are all inline functions,
+ and use TRQ internally).
+
+ Also fixed some annoying warning messages that the original TRQ
+ code generated. Also minor changes to TRQ's Makefile.in.
+
+ * Added support for querying by Client ID to both WHOIS and
+ IDENTIFY commands into server, as required by the protocol.
+
+ * Removed method function pointers from SilcBuffer structure. They
+ weren't used to anything and just increased the context size for
+ no good reason. This change also made silc_buffer_alloc and
+ silc_buffer_free functions inline functions.
+
+ * Disabled command flooding detection support until it's fixed so
+ that it accepts commands in but does not execute them more than once
+ in two seconds.
+
+ * Added silc_net_localhost(), to return local hostname, into
+ lib/silcutil/silcnet.[ch]. Also added client->hostname pointer
+ that must be initialized before calling silc_client_init.
+
+ * Added new function: silc_server_send_notify_on_channels to send
+ notify messages to all channels client has joined. It is assured
+ that the message is sent only once per client.
+
+ * Moved silc_log_format (from lib/silcutil/silclog.[ch] into
+ lib/silcutil/silcutil.[ch] as silc_format function. The new
+ function is generic and is used by server as well, not only by
+ the logging routines.
+
+ * Added new SKE status type: SILC_SKE_STATUS_BAD_VERSION to indicate
+ the provided version string was not acceptable. Added new function:
+ silc_ske_check_version into lib/silcske/silcske.h. The function
+ must be implemented by the application (client or server) and it
+ does not reside in the SKE library. The function checks the version
+ string remote end sent.
+
+ * Added back pointers (to opaque context and to SilcSocketConnection)
+ into SilcPacketContext structure into lib/silccore/silcpacket.h.
+
+ * Added silc_packet_context_dup into lib/silccore/silcpacket.[ch] to
+ duplicate packet context structure.
+
+ * Changed `notify' client operation to send same arguments as client
+ receives from server except for ID's. ID's are mapped to correct
+ ID entry and that is returned. Also, if channel entry is not sent
+ by server but the notify is for channel the channel entry is sent
+ to application (otherwise application doesn't know that it is for
+ channel (library gets it from packet's Destination ID)).
+
+ * Added silc_client_remove_from_channels into client library to
+ remove a client from all channels it has joined to. Used when
+ received SIGNOFF notify from server. Added also new function
+ silc_client_replace_from_channels to replace old ID entry with
+ new ID entry on all channels. Used when received NICK_CHANGE
+ notify from server.
+
+ * Fixed ID Cache list handling in silc_idlist_get_client in
+ lib/silcclient/idlist.c. Also, added silc_idlist_get_client_by_id
+ to get (or query) client by ID.
+
+ * Updated TODO list.
+
+ * Added connection authentication status message defined by the
+ protocol: SILC_CONN_AUTH_OK and SILC_CONN_AUTH_FAILED and added the
+ support for these into the code in client and server side.
+
+ * Added generic function silc_client_send_command to send any command
+ with variable argument list. Application should use this function
+ to send commands if the command functions provided by the library
+ does not suite for the application's user interface needs.
+
+ * Added new `failure' client operation. Application is notified about
+ received failure packet if client is executing a protocol. In this
+ case the protocol's execution has failed.
+
+ * Added SKE's end notify to send the SKE_SUCCESS notify message that
+ is required by the protocol.
+
+ * Added SILC_PROTOCOL_STATE_FAILURE to indicate received failure
+ packet from remote. SILC_PROTOCOL_STATE_ERROR indicates local
+ error at our end.
+
+ * Added status flag to SilcSKE object to indicate realtime status
+ of the SKE protocol.
+
+ * Application receives now exactly same command reply arguments as
+ the library receives from server. However, if ID is received the
+ corresponding ID entry is returned to the application (eg. Client
+ ID is mapped to correct SilcClientEntry entry and that is returned).
+ Changed command_reply client operation due to this change.
+
+ * Changed all ID's in commands and in command replys as ID Payloads.
+ Change affected both client and server side codes.
+
+ All ID's sent in SILC network (with execption of ID's in SILC
+ Packet header) are sent in ID Payload to support variable length
+ ID's.
+
+ * Server now notifies nick changes and notifies all clients on
+ the channels about the new nickname (about the new Client ID,
+ actually).
+
+ * Implemented CMODE command to change channel modes. Supports all
+ channel modes defined by the protocol specs except ban and invite
+ lists. (Also, private channel key mode is supported but support for
+ setting private channel key in client is missing, thus, this mode
+ has no effect on client side (except that server requires that the
+ client uses private channel key and normal channel traffic does not
+ work anymore)).
+
+ Also, invite mode works per se, but INVITE command does not work
+ yet correctly, so you can set channel as invite only channel but
+ inviting clients to the channel does not work (it is yet to be
+ thought what's the best way to do it).
+
+ * Added new command SILC_COMMAND_CUMODE to change user mode on the
+ channel. Defined user modes: CHANNEL_FOUNDER and CHANNEL_OPERATOR.
+ Implemented CUMODE command to change user's mode on the channel.
+ Supports all modes defined by the protocol specs.
+
+ * Added NAMES command reply to return users modes on the channel.
+
+ * Removed unnecessary and slow ciphers from lib/silccrypt.
+
+ * Set SO_KEEPALIVE option to connection sockets by default.
+
+ * Added new command reply status: SILC_STATUS_USER_NOT_ON_CHANNEL.
+
+ * Added notify types: MOTD, CMODE_CHANGE and CUMODE_CHANGE. Also,
+ redefined the Notify Payload into protocol specs.
+
+ * Added silc_id_payload_parse_id to get ID directly from raw
+ ID payload data.
+
Mon Oct 9 20:57:02 EEST 2000 Pekka Riikonen <priikone@poseidon.pspt.fi>
* Changed SILC_COMMAND_IDENTIFY in protocol specification to
Leaves the channel. If /leave * is given the client
leaves the current channel.
+ /CMODE <channel> +|-<modes> [{ <arguments>}]
+
+ Changes/sets channel mode. Most of the modes require
+ special privileges, such as channel operator or channel
+ founder privileges to work. The mode is added by adding
+ + before the option(s) and removed by adding - before
+ the option(s). Following modes are available:
+
+ p Set/unset channel as private channel
+ s Set/unset channel as secret channel
+ k Set/unset that channel uses private channel key
+ i Set/unset channel as invite only channel
+ t Set/unset that only channel operator or
+ founder may set channel topic
+ l <limit> Set/unset channel's user limit
+ a <passphrase> Set/unset passphrase for channel that must
+ be provided when joining to the channel.
+ b <username!nickname@server>
+ Add client to/remove client from ban list
+ I <username!nickname@server>
+ Add client to/remove client from invite list
+ c <cipher>[:<keylen>]
+ Set/unset channel's cipher
+
+ Multiple modes can be set/unset at once if the modes does not
+ require any arguments. If mode requires an argument then only
+ one mode can be set at once.
+
+ /CUMODE <channel> +|-<modes> <nickname>[@<server>]
+
+ Changes/set user's mode on a channel. Most of the modes
+ require that the client who changes some client's mode must
+ be channel founder or channel operator. Following channel
+ user modes are available:
+
+ a <nickname>[@<server>]
+ Set/unset all modes (cannot be used to set
+ both founder and operator rights, can be used
+ only to remove both modes at once).
+ f <nickname>[@<server>]
+ Unset channel founder. Channel founder rights
+ cannot be set by user (only by server) so this
+ can be used only to unset the mode.
+ o <nickname>[@<server>]
+ Set/unset channel operator. Requires that
+ you are channel operator or channel founder.
+
/MSG <nickname> <message>
Sends private message to remote client. Support for
New features TODO
=================
+ o We should replace all short, int, long, unsigned short, unsigned int,
+ unsigned long with some pre-defined datatypes that really are what
+ we want on all platforms. int16, uint16, int32, uint32 etc. are
+ what we could use or maybe SilcInt16, SilcUInt16 etc. Also, boolean
+ datatype should be defined.
+
+ o Add boolean (or bool), typedef of unsigned char.
+
+ o More platform supports should be added. The code is pretty much
+ generic but there are some parts that require porting (SIM). Also,
+ some support for different platforms is needed into configure.in.
+
+ o SILC requires currently GCC to work because we use GCC specific
+ compilation options. Generally any compiler that supports inline
+ functions and can build shared libraries (for SIMs) should work.
+ These cases should be included into configure.in.
+
o Extended SIM (SILC Module) support. Currently only SILC Cipher API
and SILC Hash API may be used as SIM's. What I have in mind is to
have extended support for SIM's so that basically any SILC API could
example code (code that we could use directly pretty easily) for
other platforms.
- o We should replace all short, int, long, unsigned short, unsigned int,
- unsigned long with some pre-defined datatypes that really are what
- we want on all platforms. int16, uint16, int32, uint32 etc. are
- what we could use or maybe SilcInt16, SilcUInt16 etc. Also, boolean
- datatype should be defined.
-
- o More platform supports should be added. The code is pretty much
- generic but there are some parts that require porting (SIM). Also,
- some support for different platforms is needed into configure.in.
-
- o SILC requires currently GCC to work because we use GCC specific
- compilation options. Generally any compiler that supports inline
- functions and can build shared libraries (for SIMs) should work.
- These cases should be included into configure.in.
-
-
-TODO In SILC Client
-===================
-
- o Implement all commands. A lot of commands are still yet to be
- implemented. Most of them are trivial but some will require some
- planning. Go see the command.c for unimplemented commands.
+TODO In SILC Client Library
+===========================
o Non-blocking connection on the background must be stopped if some
other connection on same window has established. Now it is possible
we already have a working connection to some other place; things
goes bad.
- o Finish WHOIS, finish JOIN and other commands that are partly
- implemented.
-
o Input line on UI is buggy. Cursor movement etc bugs. Too lazy to
fix it.
from file and using them (see corresponding code in server, it should
support public key authentication already).
- o Multiple windows support. Basic support for multiple windows already
- exists but a lot is still missing to get it working. Also, some
- of the existing stuff probably needs to be tweaked a bit before the
- multiple windows support could be done. And of course the actual
- commands that control the windows needs to be written (/WINDDOW).
-
- o Implement /KEYMAP (or similiar) command to remap control and function
- keys.
-
- o Implement /ALIAS command to make command aliases.
-
- o Implement /set/if/do/while etc as in IRC2. Maybe post 1.0 task.
- Some scripting would be good.
-
o Connection Authentication request resolving is missing and must be
done. This is required by the protocol.
+ o Move ssh_client_notify_by_server to its own file (like notify.[ch]).
+
o Key Exchange protocol's responder side is missing from client.
Generally it is possible for the client to be responder so it should
be implemented (See corresponding code from server). Error handling
in the KE protocol is also in pretty bad shape in client.
- o Configuration file format - could be better.
-
- o Write help files for commands. Nice format for the help files should
- be selected. I'm open for ideas.
-
- o All allocations and freeing needs to be checked for memory leaks.
-
TODO In SILC Server
===================
- o Implement all commands on server side. A lot of commands are still yet
- to be implemented. Most of them are trivial but some will require some
- planning. Go see the command.c for unimplemented commands.
-
o DNS/IP lookup blocks the server. This must be fixed. Check the
resolver stuff (resolver(3), resolver(5)). Either we have to do the
own resolver stuff (through scheduler, if possible without writing
o Client history must be implemented. Protocol says that server must
keep history information about clients for some period of time.
- o Channel flags and user modes on channels are not implemented yet as
- /MODE command is not implemented yet in client and server.
-
o Protocol execution timeouts are hard coded, should be configurable.
- o serverutil.c I guess should be created for util-like functions that
- now resides in server.c, which is getting too big.
-
o serverconfig.c and the function naming in it is inconsistent. It is
not silc_config_server* it should be silc_server_config*. As should
all the SilcConfigServer* types be SilcServerConfig*.
o Statistics are totally missing from the server. It would be nice
to gather some statistics.
- o All allocations and freeing needs to be checked for memory leaks.
-
TODO In SILC Libraries
======================
server, actually). If PFS is set, re-key must cause new key exchange.
This is required by the SILC protocol.
- o Re-key in general is actually missing (from everywhere) and must be done.
+ o silc_id_str2id must also take ID length as argument. Otherwise, variable
+ length ID's (after we add IPv6) will not work.
- o SKE does not send correct status types. Types are defined but not
- sent.
+ o Re-key in general is actually missing (from everywhere) and must be done.
- o Connection authentication protocol does not send correct status types.
- These types are not defined currently at all.
+ o ID Cache expiry does not work.
o PKCS#1 style RSA public key encryption/decryption/sign/verify is
missing, and should be added for interoperability reasons. The thing
I've done now is bad and should be removed as soon as possible (or
the protocol should then state the method of how they should be done).
- o Slow ciphers should be removed. I think we don't need more than
- the AES finalists plus blowfish and RC5.
-
- o These slow ciphers actually don't work currently as I've tested
- only the ones that are worth testing. The CBC mode on these slow
- ciphers probably don't work. No need to worry, these ciphers should
- be removed.
-
o Scheduler needs to be analyzed on high load as it might be unfair
towards select() because it may run timeout tasks before select() and
after select(). If it is found to be unfair the timeout task running
cleaner. Introducing silc_cipher_encrypt/decrypt/set_key etc.
functions (I actually don't understand why have I left these un-done).
- o Packet processing routines in client and server are actually pretty
- much generic and should be moved from the client/server to the library
- as generic routines (silc_<client/server>_packet_decrypt_rest* etc).
- This requires heavy changes to the client and server.
-
o Random Number Generator needs some tweaking. Reading /dev/random may
block resulting slow initialization of RNG. Some other things in the
RNG may block as well. Also, I have some pending changes to the RNG
that needs to be commited (from Schneier's Yarrow-160 paper). They
should make the RNG even better.
- o Logging should be made more generic in a way that application can
- set to where the logging is destined to. Now, it is always destined
- to stdout (or stderr) which is a bad thing for client. Ie. some
- sort of logging registration functions or similiar should be done
- (silclog.[ch] in core). The actual output of logs should be done
- by callback function in the application not in lib.
-
- o All allocations and freeing needs to be checked for memory leaks.
-
o silc_buffer_[un]format() needs to be made more stable as it may
crash the SILC if malformed data is sent as argument. There are a
lot of places in client and server where we trust directly data coming
nice as SSH is widely used all over the place. SILC Protocol
supports SSH2 public keys.
- o IRC support for SILC client. This would be nice to have on client
- as it could be used to connect to SILC and IRC. People wouldn't
- have to have two different clients when same would work on both.
- I'd like to see this done as SIM, after the extended SIM support
- has been added to SILC.
-
o Cipher optimizations (asm, that this) at least for i386 would be nice.
INCLUDES = -I. -I.. -I../lib/silccore -I../lib/silccrypt \
-I../lib/silcmath -I../lib/silcske -I../lib/silcsim \
-I../includes -I../lib/silcclient -I../lib/silcutil \
- -I../lib/silcmath/gmp
+ -I../lib/silcmath/gmp -I../lib/trq
}
-/* Notify message to the client. The `notify_payload' is the Notify
- Payload received from server. Client library may parse it to cache
- some data received from the payload but it is the application's
- responsiblity to retrieve the message and arguments from the payload.
- The message in the payload sent by server is implementation specific
- thus it is recommended that application will generate its own message. */
-/* XXX should generate own messages based on notify type. */
+/* Notify message to the client. The notify arguments are sent in the
+ same order as servers sends them. The arguments are same as received
+ from the server except for ID's. If ID is received application receives
+ the corresponding entry to the ID. For example, if Client ID is received
+ application receives SilcClientEntry. Also, if the notify type is
+ for channel the channel entry is sent to application (even if server
+ does not send it). */
void silc_notify(SilcClient client, SilcClientConnection conn,
- SilcNotifyPayload notify_payload)
+ SilcNotifyType type, ...)
{
- SilcNotifyType type;
- SilcArgumentPayload args;
+ SilcClientInternal app = (SilcClientInternal)client->application;
+ va_list vp;
char message[4096];
- char *msg;
+ SilcClientEntry client_entry, client_entry2;
+ SilcChannelEntry channel_entry;
+ char *tmp;
+ unsigned int tmp_int;
- type = silc_notify_get_type(notify_payload);
- msg = silc_notify_get_message(notify_payload);
- args = silc_notify_get_args(notify_payload);
+ va_start(vp, type);
memset(message, 0, sizeof(message));
/* Get arguments (defined by protocol in silc-pp-01 -draft) */
switch(type) {
case SILC_NOTIFY_TYPE_NONE:
- strncat(message, msg, strlen(msg));
+ tmp = va_arg(vp, char *);
+ if (!tmp)
+ return;
+ strcpy(message, tmp);
break;
+
case SILC_NOTIFY_TYPE_INVITE:
- snprintf(message, sizeof(message), msg,
- silc_argument_get_arg_type(args, 1, NULL),
- silc_argument_get_arg_type(args, 2, NULL));
+ client_entry = va_arg(vp, SilcClientEntry);
+ channel_entry = va_arg(vp, SilcChannelEntry);
+ snprintf(message, sizeof(message), "%s invites you to channel %s",
+ client_entry->nickname, channel_entry->channel_name);
break;
+
case SILC_NOTIFY_TYPE_JOIN:
- snprintf(message, sizeof(message), msg,
- silc_argument_get_arg_type(args, 2, NULL),
- silc_argument_get_arg_type(args, 3, NULL),
- silc_argument_get_arg_type(args, 4, NULL),
- silc_argument_get_arg_type(args, 6, NULL));
+ client_entry = va_arg(vp, SilcClientEntry);
+ channel_entry = va_arg(vp, SilcChannelEntry);
+ snprintf(message, sizeof(message), "%s (%s) has joined channel %s",
+ client_entry->nickname, client_entry->username,
+ channel_entry->channel_name);
break;
+
case SILC_NOTIFY_TYPE_LEAVE:
- snprintf(message, sizeof(message), msg,
- silc_argument_get_arg_type(args, 1, NULL),
- silc_argument_get_arg_type(args, 2, NULL),
- silc_argument_get_arg_type(args, 4, NULL));
+ client_entry = va_arg(vp, SilcClientEntry);
+ channel_entry = va_arg(vp, SilcChannelEntry);
+ if (client_entry->server)
+ snprintf(message, sizeof(message), "%s@%s has left channel %s",
+ client_entry->nickname, client_entry->server,
+ channel_entry->channel_name);
+ else
+ snprintf(message, sizeof(message), "%s has left channel %s",
+ client_entry->nickname, channel_entry->channel_name);
break;
+
case SILC_NOTIFY_TYPE_SIGNOFF:
- snprintf(message, sizeof(message), msg,
- silc_argument_get_arg_type(args, 1, NULL),
- silc_argument_get_arg_type(args, 2, NULL));
+ client_entry = va_arg(vp, SilcClientEntry);
+ if (client_entry->server)
+ snprintf(message, sizeof(message), "Signoff: %s@%s",
+ client_entry->nickname, client_entry->server);
+ else
+ snprintf(message, sizeof(message), "Signoff: %s",
+ client_entry->nickname);
break;
+
case SILC_NOTIFY_TYPE_TOPIC_SET:
- snprintf(message, sizeof(message), msg,
- silc_argument_get_arg_type(args, 3, NULL),
- silc_argument_get_arg_type(args, 4, NULL),
- silc_argument_get_arg_type(args, 2, NULL));
+ client_entry = va_arg(vp, SilcClientEntry);
+ tmp = va_arg(vp, char *);
+ channel_entry = va_arg(vp, SilcChannelEntry);
+ if (client_entry->server)
+ snprintf(message, sizeof(message), "%s@%s set topic on %s: %s",
+ client_entry->nickname, client_entry->server,
+ channel_entry->channel_name, tmp);
+ else
+ snprintf(message, sizeof(message), "%s set topic on %s: %s",
+ client_entry->nickname, channel_entry->channel_name, tmp);
+ break;
+
+ case SILC_NOTIFY_TYPE_NICK_CHANGE:
+ client_entry = va_arg(vp, SilcClientEntry);
+ client_entry2 = va_arg(vp, SilcClientEntry);
+ if (client_entry->server && client_entry2->server)
+ snprintf(message, sizeof(message), "%s@%s is known as %s@%s",
+ client_entry->nickname, client_entry->server,
+ client_entry2->nickname, client_entry2->server);
+ else
+ snprintf(message, sizeof(message), "%s is known as %s",
+ client_entry->nickname, client_entry2->nickname);
break;
+
+ case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+ client_entry = va_arg(vp, SilcClientEntry);
+ tmp = silc_client_chmode(va_arg(vp, unsigned int));
+ channel_entry = va_arg(vp, SilcChannelEntry);
+ if (tmp)
+ snprintf(message, sizeof(message), "%s changed channel mode to +%s",
+ client_entry->nickname, tmp);
+ else
+ snprintf(message, sizeof(message), "%s removed all channel modes",
+ client_entry->nickname);
+ if (app->screen->bottom_line->channel_mode)
+ silc_free(app->screen->bottom_line->channel_mode);
+ app->screen->bottom_line->channel_mode = tmp;
+ silc_screen_print_bottom_line(app->screen, 0);
+ break;
+
+ case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+ client_entry = va_arg(vp, SilcClientEntry);
+ tmp_int = va_arg(vp, unsigned int);
+ tmp = silc_client_chumode(tmp_int);
+ client_entry2 = va_arg(vp, SilcClientEntry);
+ channel_entry = va_arg(vp, SilcChannelEntry);
+ if (tmp)
+ snprintf(message, sizeof(message), "%s changed %s mode to +%s",
+ client_entry->nickname, client_entry2->nickname, tmp);
+ else
+ snprintf(message, sizeof(message), "%s removed %s modes",
+ client_entry->nickname, client_entry2->nickname);
+ if (client_entry2 == conn->local_entry) {
+ if (app->screen->bottom_line->mode)
+ silc_free(app->screen->bottom_line->mode);
+ app->screen->bottom_line->mode = silc_client_chumode_char(tmp_int);
+ silc_screen_print_bottom_line(app->screen, 0);
+ }
+ silc_free(tmp);
+ break;
+
+ case SILC_NOTIFY_TYPE_MOTD:
+ {
+ char line[256];
+ int i;
+ tmp = va_arg(vp, unsigned char *);
+
+ i = 0;
+ while(tmp[i] != 0) {
+ if (tmp[i++] == '\n') {
+ memset(line, 0, sizeof(line));
+ strncat(line, tmp, i - 1);
+ tmp += i;
+
+ silc_say(client, conn, "%s", line);
+
+ if (!strlen(tmp))
+ break;
+ i = 0;
+ }
+ }
+ }
+ return;
+
default:
break;
}
void silc_command_reply(SilcClient client, SilcClientConnection conn,
SilcCommandPayload cmd_payload, int success,
- SilcCommandStatus status, SilcCommand command, ...)
+ SilcCommand command, SilcCommandStatus status, ...)
{
SilcClientInternal app = (SilcClientInternal)client->application;
va_list vp;
+ int i;
if (!success)
return;
- va_start(vp, command);
+ va_start(vp, status);
switch(command)
{
case SILC_COMMAND_JOIN:
- app->screen->bottom_line->channel = va_arg(vp, char *);
- silc_screen_print_bottom_line(app->screen, 0);
+ {
+ unsigned int mode;
+
+ app->screen->bottom_line->channel = va_arg(vp, char *);
+ (void)va_arg(vp, void *);
+ mode = va_arg(vp, unsigned int);
+ app->screen->bottom_line->channel_mode = silc_client_chmode(mode);
+ silc_screen_print_bottom_line(app->screen, 0);
+ }
break;
case SILC_COMMAND_NICK:
- app->screen->bottom_line->nickname = va_arg(vp, char *);
- silc_screen_print_bottom_line(app->screen, 0);
+ {
+ SilcClientEntry entry;
+
+ entry = va_arg(vp, SilcClientEntry);
+ silc_say(client, conn, "Your current nickname is %s", entry->nickname);
+ app->screen->bottom_line->nickname = entry->nickname;
+ silc_screen_print_bottom_line(app->screen, 0);
+ }
break;
+ case SILC_COMMAND_NAMES:
+ for (i = 0; i < conn->current_channel->clients_count; i++)
+ if (conn->current_channel->clients[i].client == conn->local_entry) {
+ if (app->screen->bottom_line->mode)
+ silc_free(app->screen->bottom_line->mode);
+ app->screen->bottom_line->mode =
+ silc_client_chumode_char(conn->current_channel->clients[i].mode);
+ silc_screen_print_bottom_line(app->screen, 0);
+ break;
+ }
+ break;
}
}
return FALSE;
}
+/* Notifies application that failure packet was received. This is called
+ if there is some protocol active in the client. The `protocol' is the
+ protocol context. The `failure' is opaque pointer to the failure
+ indication. Note, that the `failure' is protocol dependant and application
+ must explicitly cast it to correct type. Usually `failure' is 32 bit
+ failure type (see protocol specs for all protocol failure types). */
+
+void silc_failure(SilcClient client, SilcClientConnection conn,
+ SilcProtocol protocol, void *failure)
+{
+ SilcClientInternal app = (SilcClientInternal)client->application;
+
+}
+
/* SILC client operations */
SilcClientOperations ops = {
say: silc_say,
get_auth_method: silc_get_auth_method,
verify_server_key: silc_verify_server_key,
ask_passphrase: silc_ask_passphrase,
+ failure: silc_failure,
};
void silc_private_message(SilcClient client, SilcClientConnection conn,
char *sender, char *msg);
void silc_notify(SilcClient client, SilcClientConnection conn,
- SilcNotifyPayload notify_payload);
+ SilcNotifyType type, ...);
void silc_command(SilcClient client, SilcClientConnection conn,
SilcClientCommandContext cmd_context, int success,
SilcCommand command);
void silc_command_reply(SilcClient client, SilcClientConnection conn,
SilcCommandPayload cmd_payload, int success,
- SilcCommandStatus status, SilcCommand command, ...);
+ SilcCommand command, SilcCommandStatus status, ...);
void silc_connect(SilcClient client, SilcClientConnection conn, int success);
void silc_disconnect(SilcClient client, SilcClientConnection conn);
unsigned char *silc_ask_passphrase(SilcClient client,
SilcProtocolAuthMeth *auth_meth,
unsigned char **auth_data,
unsigned int *auth_data_len);
+void silc_failure(SilcClient client, SilcClientConnection conn,
+ SilcProtocol protocol, void *failure);
#endif
return TRUE;
}
+
+/* Parses mode mask and returns the mode as string. */
+
+char *silc_client_chmode(unsigned int mode)
+{
+ char string[20];
+
+ if (!mode)
+ return NULL;
+
+ memset(string, 0, sizeof(string));
+
+ if (mode & SILC_CHANNEL_MODE_PRIVATE)
+ strncat(string, "p", 1);
+
+ if (mode & SILC_CHANNEL_MODE_SECRET)
+ strncat(string, "s", 1);
+
+ if (mode & SILC_CHANNEL_MODE_PRIVKEY)
+ strncat(string, "k", 1);
+
+ if (mode & SILC_CHANNEL_MODE_INVITE)
+ strncat(string, "i", 1);
+
+ if (mode & SILC_CHANNEL_MODE_TOPIC)
+ strncat(string, "t", 1);
+
+ if (mode & SILC_CHANNEL_MODE_ULIMIT)
+ strncat(string, "l", 1);
+
+ if (mode & SILC_CHANNEL_MODE_PASSPHRASE)
+ strncat(string, "a", 1);
+
+ /* Rest of mode is ignored */
+
+ return strdup(string);
+}
+
+/* Parses channel user mode mask and returns te mode as string */
+
+char *silc_client_chumode(unsigned int mode)
+{
+ char string[4];
+
+ if (!mode)
+ return NULL;
+
+ memset(string, 0, sizeof(string));
+
+ if (mode & SILC_CHANNEL_UMODE_CHANFO)
+ strncat(string, "f", 1);
+
+ if (mode & SILC_CHANNEL_UMODE_CHANOP)
+ strncat(string, "o", 1);
+
+ return strdup(string);
+}
+
+/* Parses channel user mode and returns it as special mode character. */
+
+char *silc_client_chumode_char(unsigned int mode)
+{
+ char string[4];
+
+ if (!mode)
+ return NULL;
+
+ memset(string, 0, sizeof(string));
+
+ if (mode & SILC_CHANNEL_UMODE_CHANFO)
+ strncat(string, "*", 1);
+
+ if (mode & SILC_CHANNEL_UMODE_CHANOP)
+ strncat(string, "@", 1);
+
+ return strdup(string);
+}
SilcPrivateKey *ret_prv_key);
int silc_client_check_silc_dir();
int silc_client_load_keys(SilcClient client);
+char *silc_client_chmode(unsigned int mode);
+char *silc_client_chumode(unsigned int mode);
+char *silc_client_chumode_char(unsigned int mode);
#endif
* old version of the SILC client dating back to 1997.
*/
/* XXX: Input line handling is really buggy! */
-/*
- * $Id$
- * $Log$
- * Revision 1.5 2000/07/19 09:19:05 priikone
- * Enhancements to AWAY command.
- *
- * Revision 1.4 2000/07/10 05:38:08 priikone
- * Fixed screen refresh.
- *
- * Revision 1.3 2000/07/07 06:52:10 priikone
- * Fixed screen refresh routine.
- *
- * Revision 1.2 2000/07/05 06:12:05 priikone
- * Global cosmetic changes.
- *
- * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
- * Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
#include "clientincludes.h"
SILC_SCREEN_MAX_CHANNEL_LEN : len);
}
+ if (line->channel_mode) {
+ len = strlen(line->channel_mode);
+ strncat(buf, " (+", 3);
+ strncat(buf, line->channel_mode, len > SILC_SCREEN_MAX_CHANNEL_LEN ?
+ SILC_SCREEN_MAX_CHANNEL_LEN : len);
+ strncat(buf, ")", 2);
+ }
+
if (line->away)
strncat(buf, " (away)", 8);
char *nickname;
char *connection;
char *channel;
+ char *channel_mode;
int away;
} *SilcScreenBottomLine;
/* 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. */
INCLUDES = -I. -I.. -I../lib/silccore -I../lib/silccrypt \
-I../lib/silcmath -I../lib/silcske -I../lib/silcsim \
-I../includes -I../lib/silcutil \
- -I../lib/silcmath/gmp
+ -I../lib/silcmath/gmp -I../lib/trq
SILC_SERVER_CMD(motd, MOTD, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(umode, UMODE, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(cmode, CMODE, SILC_CF_LAG | SILC_CF_REG),
+ SILC_SERVER_CMD(cumode, CUMODE, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(kick, KICK, SILC_CF_LAG | SILC_CF_REG),
SILC_SERVER_CMD(restart, RESTART,
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER),
SilcServerCommandContext ctx;
SilcServerCommand *cmd;
+#if 0
/* Check whether it is allowed for this connection to execute any
command. */
if (sock->type == SILC_SOCKET_TYPE_CLIENT) {
/* Update access time */
client->last_command = curtime;
}
+#endif
/* Allocate command context. This must be free'd by the
command routine receiving it. */
SilcServer server = cmd->server;
char *tmp, *nick = NULL, *server_name = NULL;
unsigned int i, argc, count = 0, len, clients_count;
- SilcClientEntry entry;
- SilcBuffer packet;
- unsigned char *id_string;
- SilcClientEntry *clients;
+ int use_id = FALSE;
+ SilcClientID *client_id = NULL;
+ SilcBuffer packet, idp;
+ SilcClientEntry *clients = NULL, entry;
SilcCommandStatus status;
SILC_LOG_DEBUG(("Start"));
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- if (argc > 2) {
+ if (argc > 3) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
SILC_STATUS_ERR_TOO_MANY_PARAMS);
goto out;
}
- /* Get the nickname@server string and parse it. */
- tmp = silc_argument_get_first_arg(cmd->args, NULL);
- if (tmp) {
- if (strchr(tmp, '@')) {
- len = strcspn(tmp, "@");
- nick = silc_calloc(len + 1, sizeof(char));
- memcpy(nick, tmp, len);
- server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
- memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+ /* If client ID is in the command it must be used instead of nickname */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp) {
+
+ /* No ID, get the nickname@server string and parse it. */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp) {
+ if (strchr(tmp, '@')) {
+ len = strcspn(tmp, "@");
+ nick = silc_calloc(len + 1, sizeof(char));
+ memcpy(nick, tmp, len);
+ server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+ memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+ } else {
+ nick = strdup(tmp);
+ }
} else {
- nick = strdup(tmp);
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
}
} else {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ /* Command includes ID, use that */
+ client_id = silc_id_payload_parse_id(tmp, len);
+ use_id = TRUE;
}
/* Get the max count of reply messages allowed */
- if (argc == 2) {
- tmp = silc_argument_get_next_arg(cmd->args, NULL);
+ if (argc == 3) {
+ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_WHOIS,
SILC_STATUS_ERR_TOO_MANY_PARAMS);
}
/* Get all clients matching that nickname */
- clients = silc_idlist_get_clients_by_nickname(server->local_list,
- nick, server_name,
- &clients_count);
- if (!clients) {
+ if (!use_id) {
+ clients = silc_idlist_get_clients_by_nickname(server->local_list,
+ nick, server_name,
+ &clients_count);
+ } else {
+ entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+ if (entry) {
+ clients = silc_calloc(1, sizeof(*clients));
+ clients[0] = entry;
+ clients_count = 1;
+ }
+ }
+ if (!clients) {
+
/* If we are normal server and are connected to a router we will
make global query from the router. */
if (server->server_type == SILC_SERVER && !server->standalone) {
}
ok:
- /* XXX, works only for local server info */
+ /* XXX, works only for local server info */
status = SILC_STATUS_OK;
if (clients_count > 1)
status = SILC_STATUS_LIST_END;
/* Send WHOIS reply */
- id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
/* XXX */
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
status, 0, 5,
- 2, id_string, SILC_ID_CLIENT_LEN,
+ 2, idp->data, idp->len,
3, nh, strlen(nh),
4, uh, strlen(uh),
5, entry->userinfo,
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
status, 0, 4,
- 2, id_string, SILC_ID_CLIENT_LEN,
+ 2, idp->data, idp->len,
3, nh, strlen(nh),
4, uh, strlen(uh),
7, idle, 4);
packet =
silc_command_reply_payload_encode_va(SILC_COMMAND_WHOIS,
status, 0, 3,
- 2, id_string, SILC_ID_CLIENT_LEN,
+ 2, idp->data, idp->len,
3, entry->nickname,
strlen(entry->nickname),
4, tmp, strlen(tmp)); /* XXX */
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
- silc_free(id_string);
silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ silc_free(clients);
}
-
+
+ if (client_id)
+ silc_free(client_id);
+
out:
silc_server_command_free(cmd);
}
SilcServer server = cmd->server;
char *tmp, *nick = NULL, *server_name = NULL;
unsigned int argc, count = 0, len;
+ int use_id = FALSE;
+ SilcClientID *client_id = NULL;
SilcClientEntry entry;
- SilcBuffer packet;
- unsigned char *id_string;
+ SilcBuffer packet, idp;
SILC_LOG_DEBUG(("Start"));
SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
goto out;
}
- if (argc > 2) {
+ if (argc > 3) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_TOO_MANY_PARAMS);
goto out;
}
- /* Get the nickname@server string and parse it. */
- tmp = silc_argument_get_first_arg(cmd->args, NULL);
- if (tmp) {
- if (strchr(tmp, '@')) {
- len = strcspn(tmp, "@");
- nick = silc_calloc(len + 1, sizeof(char));
- memcpy(nick, tmp, len);
- server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
- memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+ /* If client ID is in the command it must be used instead of nickname */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp) {
+
+ /* Get the nickname@server string and parse it. */
+ tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ if (tmp) {
+ if (strchr(tmp, '@')) {
+ len = strcspn(tmp, "@");
+ nick = silc_calloc(len + 1, sizeof(char));
+ memcpy(nick, tmp, len);
+ server_name = silc_calloc(strlen(tmp) - len, sizeof(char));
+ memcpy(server_name, tmp + len + 1, strlen(tmp) - len - 1);
+ } else {
+ nick = strdup(tmp);
+ }
} else {
- nick = strdup(tmp);
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
}
} else {
- silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
- SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
- goto out;
+ /* Command includes ID, use that */
+ client_id = silc_id_payload_parse_id(tmp, len);
+ use_id = TRUE;
}
/* Get the max count of reply messages allowed */
- if (argc == 2) {
- tmp = silc_argument_get_next_arg(cmd->args, NULL);
+ if (argc == 3) {
+ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_IDENTIFY,
SILC_STATUS_ERR_TOO_MANY_PARAMS);
}
/* Find client */
- entry = silc_idlist_find_client_by_nickname(server->local_list,
- nick, NULL);
- if (!entry)
- entry = silc_idlist_find_client_by_hash(server->global_list,
- nick, server->md5hash);
+ if (!use_id) {
+ entry = silc_idlist_find_client_by_nickname(server->local_list,
+ nick, NULL);
+ if (!entry)
+ entry = silc_idlist_find_client_by_hash(server->global_list,
+ nick, server->md5hash);
+ } else {
+ entry = silc_idlist_find_client_by_id(server->local_list, client_id);
+ }
/* If client was not found and if we are normal server and are connected
to a router we will make global query from the router. */
}
/* Send IDENTIFY reply */
- id_string = silc_id_id2str(entry->id, SILC_ID_CLIENT);
+ idp = silc_id_payload_encode(entry->id, SILC_ID_CLIENT);
tmp = silc_argument_get_first_arg(cmd->args, NULL);
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_IDENTIFY,
SILC_STATUS_OK, 0, 2,
- 2, id_string,
- SILC_ID_CLIENT_LEN,
+ 2, idp->data, idp->len,
3, nick, strlen(nick));
if (cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED) {
void *id = silc_id_str2id(cmd->packet->src_id, cmd->packet->src_id_type);
packet->data, packet->len, FALSE);
}
- silc_free(id_string);
silc_buffer_free(packet);
+ silc_buffer_free(idp);
+ if (client_id)
+ silc_free(client_id);
out:
if (nick)
SILC_SERVER_CMD_FUNC(nick)
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
- SilcClientEntry id_entry = (SilcClientEntry)cmd->sock->user_data;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
SilcServer server = cmd->server;
- SilcBuffer packet;
+ SilcBuffer packet, nidp, oidp;
SilcClientID *new_id;
- char *id_string;
char *nick;
SILC_LOG_DEBUG(("Start"));
ID and ask to replace it with the old one. */
if (cmd->server->server_type == SILC_SERVER && !cmd->server->standalone)
silc_server_send_replace_id(server, server->id_entry->router->connection,
- FALSE, id_entry->id,
+ FALSE, client->id,
SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
routers in SILC. */
if (cmd->server->server_type == SILC_ROUTER && !cmd->server->standalone)
silc_server_send_replace_id(server, server->id_entry->router->connection,
- TRUE, id_entry->id,
+ TRUE, client->id,
SILC_ID_CLIENT, SILC_ID_CLIENT_LEN,
new_id, SILC_ID_CLIENT, SILC_ID_CLIENT_LEN);
/* Remove old cache entry */
silc_idcache_del_by_id(server->local_list->clients, SILC_ID_CLIENT,
- id_entry->id);
-
+ client->id);
+
+ oidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
/* Free old ID */
- if (id_entry->id) {
- memset(id_entry->id, 0, SILC_ID_CLIENT_LEN);
- silc_free(id_entry->id);
+ if (client->id) {
+ memset(client->id, 0, SILC_ID_CLIENT_LEN);
+ silc_free(client->id);
}
/* Save the nickname as this client is our local client */
- if (id_entry->nickname)
- silc_free(id_entry->nickname);
+ if (client->nickname)
+ silc_free(client->nickname);
- id_entry->nickname = strdup(nick);
- id_entry->id = new_id;
+ client->nickname = strdup(nick);
+ client->id = new_id;
/* Update client cache */
- silc_idcache_add(server->local_list->clients, id_entry->nickname,
- SILC_ID_CLIENT, id_entry->id, (void *)id_entry, TRUE);
+ silc_idcache_add(server->local_list->clients, client->nickname,
+ SILC_ID_CLIENT, client->id, (void *)client, TRUE);
+
+ nidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
+ /* Send NICK_CHANGE notify */
+ silc_server_send_notify_on_channels(server, client,
+ SILC_NOTIFY_TYPE_NICK_CHANGE, 2,
+ oidp->data, oidp->len,
+ nidp->data, nidp->len);
/* Send the new Client ID as reply command back to client */
- id_string = silc_id_id2str(id_entry->id, SILC_ID_CLIENT);
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NICK,
SILC_STATUS_OK, 0, 1,
- 2, id_string,
- SILC_ID_CLIENT_LEN);
+ 2, nidp->data, nidp->len);
silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
- silc_free(id_string);
silc_buffer_free(packet);
+ silc_buffer_free(nidp);
+ silc_buffer_free(oidp);
out:
silc_server_command_free(cmd);
SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
SilcChannelID *channel_id;
SilcChannelEntry channel;
- SilcBuffer packet;
- SilcBuffer id_payload;
- unsigned char *tmp, *id_string;
- unsigned int argc;
+ SilcChannelClientEntry chl;
+ SilcBuffer packet, idp;
+ unsigned char *tmp;
+ unsigned int argc, tmp_len;
/* Check number of arguments */
argc = silc_argument_get_arg_num(cmd->args);
}
/* Get Channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
SILC_STATUS_ERR_NO_CHANNEL_ID);
goto out;
}
- channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
/* Check whether the channel exists */
channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
goto out;
}
+ /* See whether has rights to change topic */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ if (chl->client == client) {
+ if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_TOPIC,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ } else {
+ break;
+ }
+ }
+ }
+
/* Set the topic for channel */
if (channel->topic)
silc_free(channel->topic);
channel->topic = strdup(tmp);
- id_payload = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL_LEN,
- SILC_ID_CHANNEL);
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Send notify about topic change to all clients on the channel */
silc_server_send_notify_to_channel(server, channel,
- SILC_NOTIFY_TYPE_TOPIC_SET, 4, FALSE,
- "%s@%s set topic: %s",
- id_payload->data, id_payload->len,
- tmp, strlen(tmp),
- client->nickname,
- strlen(client->nickname),
- cmd->sock->hostname,
- strlen(cmd->sock->hostname));
- silc_buffer_free(id_payload);
+ SILC_NOTIFY_TYPE_TOPIC_SET, 2,
+ idp->data, idp->len,
+ channel->topic, strlen(channel->topic));
+ silc_buffer_free(idp);
}
/* Send the topic to client as reply packet */
- id_string = silc_id_id2str(channel_id, SILC_ID_CHANNEL);
+ idp = silc_id_payload_encode(channel_id, SILC_ID_CHANNEL);
if (channel->topic)
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
SILC_STATUS_OK, 0, 2,
- 2, id_string,
- SILC_ID_CHANNEL_LEN,
+ 2, idp->data, idp->len,
3, channel->topic,
strlen(channel->topic));
else
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_TOPIC,
SILC_STATUS_OK, 0, 1,
- 2, id_string,
- SILC_ID_CHANNEL_LEN);
+ 2, idp->data, idp->len);
silc_server_packet_send(cmd->server, cmd->sock, SILC_PACKET_COMMAND_REPLY,
0, packet->data, packet->len, FALSE);
- silc_free(id_string);
silc_buffer_free(packet);
+ silc_buffer_free(idp);
silc_free(channel_id);
out:
SilcClientID *dest_id;
SilcChannelEntry channel;
SilcChannelID *channel_id;
+ SilcBuffer sidp;
+ unsigned char *tmp;
unsigned int argc, len;
- unsigned char *id_string;
/* Check number of arguments */
argc = silc_argument_get_arg_num(cmd->args);
}
/* Get destination ID */
- id_string = silc_argument_get_arg_type(cmd->args, 1, &len);
- if (!id_string) {
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
SILC_STATUS_ERR_NO_CLIENT_ID);
goto out;
}
- dest_id = silc_id_str2id(id_string, SILC_ID_CLIENT);
+ dest_id = silc_id_payload_parse_id(tmp, len);
/* Get Channel ID */
- id_string = silc_argument_get_arg_type(cmd->args, 2, &len);
- if (!id_string) {
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
SILC_STATUS_ERR_NO_CHANNEL_ID);
goto out;
}
- channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+ channel_id = silc_id_payload_parse_id(tmp, len);
/* Check whether the channel exists */
channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
}
/* Check whether the sender of this command is on the channel. */
- sender = (SilcClientEntry )sock->user_data;
+ sender = (SilcClientEntry)sock->user_data;
if (!silc_server_client_on_channel(sender, channel)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
SILC_STATUS_ERR_NOT_ON_CHANNEL);
/* Check whether the channel is invite-only channel. If yes then the
sender of this command must be at least channel operator. */
- /* XXX */
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+ SilcChannelClientEntry chl;
+
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+ if (chl->client == sender) {
+ if (chl->mode == SILC_CHANNEL_UMODE_NONE) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+ break;
+ }
+ }
/* Find the connection data for the destination. If it is local we will
send it directly otherwise we will send it to router for routing. */
goto out;
}
+ sidp = silc_id_payload_encode(sender->id, SILC_ID_CLIENT);
+
/* Send notify to the client that is invited to the channel */
silc_server_send_notify_dest(server, dest_sock, dest_id, SILC_ID_CLIENT,
- SILC_NOTIFY_TYPE_INVITE, 2, FALSE,
- "%s invites you to channel %s",
- sender->nickname, strlen(sender->nickname),
- channel->channel_name,
- strlen(channel->channel_name));
+ SILC_NOTIFY_TYPE_INVITE, 2,
+ sidp->data, sidp->len, tmp, len);
/* Send command reply */
silc_server_command_send_status_reply(cmd, SILC_COMMAND_INVITE,
SILC_STATUS_OK);
+ silc_buffer_free(sidp);
+
out:
silc_server_command_free(cmd);
}
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- SilcBuffer packet;
+ SilcBuffer packet, idp;
unsigned int argc;
- unsigned char *id_string;
char info_string[256], *dest_server;
argc = silc_argument_get_arg_num(cmd->args);
server->config->admin_info->admin_name,
server->config->admin_info->admin_email);
- id_string = silc_id_id2str(server->id, SILC_ID_SERVER);
+ idp = silc_id_payload_encode(server->id, SILC_ID_SERVER);
- packet =
- silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
- SILC_STATUS_OK, 0, 2,
- 2, id_string, SILC_ID_SERVER_LEN,
- 3, info_string,
- strlen(info_string));
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_INFO,
+ SILC_STATUS_OK, 0, 2,
+ 2, idp->data, idp->len,
+ 3, info_string,
+ strlen(info_string));
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
- silc_free(id_string);
silc_buffer_free(packet);
+ silc_buffer_free(idp);
} else {
/* Send this command to the requested server */
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcServerID *id;
- unsigned int argc;
- unsigned char *id_string;
+ unsigned int argc, len;
+ unsigned char *tmp;
argc = silc_argument_get_arg_num(cmd->args);
if (argc < 1) {
}
/* Get Server ID */
- id_string = silc_argument_get_arg_type(cmd->args, 1, NULL);
- if (!id_string) {
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
+ if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_PING,
SILC_STATUS_ERR_NO_SERVER_ID);
goto out;
}
- id = silc_id_str2id(id_string, SILC_ID_SERVER);
+ id = silc_id_payload_parse_id(tmp, len);
if (!SILC_ID_SERVER_COMPARE(id, server->id)) {
/* Send our reply */
JoinInternalContext *ctx = (JoinInternalContext *)context;
if (ctx->channel->key && ctx->channel->key_len) {
- SilcBuffer channel_idp, client_idp;
+ SilcBuffer clidp;
- channel_idp = silc_id_payload_encode(ctx->channel->id, SILC_ID_CHANNEL_LEN,
- SILC_ID_CHANNEL);
- client_idp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT_LEN,
- SILC_ID_CLIENT);
+ clidp = silc_id_payload_encode(ctx->client->id, SILC_ID_CLIENT);
silc_server_send_notify_to_channel(ctx->server, ctx->channel,
- SILC_NOTIFY_TYPE_JOIN, 6, FALSE,
- "%s (%s@%s) has joined channel %s",
- client_idp->data, client_idp->len,
- ctx->nickname, strlen(ctx->nickname),
- ctx->username, strlen(ctx->username),
- ctx->hostname, strlen(ctx->hostname),
- channel_idp->data, channel_idp->len,
- ctx->channel_name,
- strlen(ctx->channel_name));
-
- silc_buffer_free(client_idp);
- silc_buffer_free(channel_idp);
+ SILC_NOTIFY_TYPE_JOIN, 1,
+ clidp->data, clidp->len);
+
+ silc_buffer_free(clidp);
silc_free(ctx);
} else {
silc_task_register(ctx->server->timeout_queue, fd,
SilcChannelEntry channel)
{
SilcServerCommandContext cmd;
- SilcBuffer buffer;
- unsigned char *id_string;
+ SilcBuffer buffer, idp;
- id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
- 1, id_string, SILC_ID_CHANNEL_LEN);
+ 1, idp->data, idp->len);
cmd = silc_calloc(1, sizeof(*cmd));
cmd->payload = silc_command_payload_parse(buffer);
cmd->pending = FALSE;
silc_server_command_names((void *)cmd);
- silc_free(id_string);
silc_free(buffer);
+ silc_free(idp);
}
/* Server side of command JOIN. Joins client into requested channel. If
SilcServer server = cmd->server;
SilcSocketConnection sock = cmd->sock;
SilcBuffer buffer = cmd->packet->buffer;
- int argc, i, tmp_len;
- char *tmp, *channel_name = NULL, *cipher = NULL, *id_string = NULL;
- unsigned char *passphrase, mode[4];
+ int argc, i, k, tmp_len;
+ char *tmp, *channel_name = NULL, *cipher = NULL;
+ unsigned char *passphrase = NULL, mode[4];
+ unsigned int umode = 0;
SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
SilcServerID *router_id;
- SilcBuffer packet;
+ SilcBuffer packet, idp;
SilcClientEntry client;
SILC_LOG_DEBUG(("Start"));
/* Get channel name */
tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
- channel_name = silc_calloc(tmp_len + 1, sizeof(*channel_name));
- memcpy(channel_name, tmp, tmp_len);
- if (silc_server_command_bad_chars(tmp) == TRUE) {
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ channel_name = tmp;
+
+ if (silc_server_command_bad_chars(channel_name) == TRUE) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_BAD_CHANNEL);
silc_free(channel_name);
the channel by ourselves. */
if (server->standalone) {
router_id = server->id;
- channel = silc_server_new_channel(server, router_id,
- cipher, channel_name);
+ channel = silc_server_new_channel(server, router_id, cipher,
+ channel_name);
+ umode |= SILC_CHANNEL_UMODE_CHANOP;
+ umode |= SILC_CHANNEL_UMODE_CHANFO;
if (!channel)
goto out;
join_channel:
+ /*
+ * Check channel modes
+ */
+
+ /* Check invite list if channel is invite-only channel */
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE) {
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
+ /* Invite list is specified. Check whether client is invited in the
+ list. If not, then check whether it has been invited otherwise. */
+
+ } else {
+ /* XXX client must be invited to be able to join the channel */
+ }
+ }
+
+ /* Check ban list if set */
+ if (channel->mode & SILC_CHANNEL_MODE_BAN) {
+
+ }
+
+ /* Check the channel passphrase if set. */
+ if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ if (!passphrase || memcmp(channel->mode_data.passphrase, passphrase,
+ strlen(channel->mode_data.passphrase))) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_BAD_PASSWORD);
+ goto out;
+ }
+ }
+
+ /* Check user count limit if set. */
+ if (channel->mode & SILC_CHANNEL_MODE_ULIMIT) {
+ if (silc_list_count(channel->user_list) + 1 >
+ channel->mode_data.user_limit) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
+ SILC_STATUS_ERR_CHANNEL_IS_FULL);
+ goto out;
+ }
+ }
+
+ /*
+ * Client is allowed to join to the channel. Make it happen.
+ */
+
/* If the JOIN request was forwarded to us we will make a bit slower
query to get the client pointer. Otherwise, we get the client pointer
real easy. */
if (silc_server_client_on_channel(client, channel)) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_JOIN,
SILC_STATUS_ERR_USER_ON_CHANNEL);
- silc_free(channel_name);
goto out;
}
- /* Join the client to the channel */
- i = channel->user_list_count;
- channel->user_list = silc_realloc(channel->user_list,
- sizeof(*channel->user_list) * (i + 1));
- channel->user_list[i].mode = SILC_CHANNEL_UMODE_NONE;
- channel->user_list[i].client = client;
- channel->user_list_count++;
+ /* Join the client to the channel by adding it to channel's user list */
+ chl = silc_calloc(1, sizeof(*chl));
+ chl->mode = umode;
+ chl->client = client;
+ silc_list_add(channel->user_list, chl);
/* Add the channel to client's channel list */
i = client->channel_count;
- client->channel = silc_realloc(client->channel,
- sizeof(*client->channel) * (i + 1));
- client->channel[i] = channel;
- client->channel_count++;
+ for (k = 0; k < client->channel_count; k++) {
+ if (client->channel[k] == NULL) {
+ client->channel[k] = channel;
+ break;
+ }
+ }
+ if (k >= i) {
+ i = client->channel_count;
+ client->channel = silc_realloc(client->channel,
+ sizeof(*client->channel) * (i + 1));
+ client->channel[i] = channel;
+ client->channel_count++;
+ }
/* Notify router about new user on channel. If we are normal server
we send it to our router, if we are router we send it to our
/* Send command reply to the client. Client receives the Channe ID,
channel mode and possibly other information in this reply packet. */
if (!cmd->pending) {
- id_string = silc_id_id2str(channel->id, SILC_ID_CHANNEL);
+ idp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
SILC_PUT32_MSB(channel->mode, mode);
if (!channel->topic)
SILC_STATUS_OK, 0, 3,
2, channel_name,
strlen(channel_name),
- 3, id_string, SILC_ID_CHANNEL_LEN,
+ 3, idp->data, idp->len,
4, mode, 4);
else
packet =
SILC_STATUS_OK, 0, 4,
2, channel_name,
strlen(channel_name),
- 3, id_string, SILC_ID_CHANNEL_LEN,
+ 3, idp->data, idp->len,
4, mode, 4,
5, channel->topic,
strlen(channel->topic));
} else
silc_server_packet_send(server, sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
-
silc_buffer_free(packet);
- }
- /* Send channel key to the client. Client cannot start transmitting
- to the channel until we have sent the key. */
- if (!cmd->pending) {
+ /* Send channel key to the client. Client cannot start transmitting
+ to the channel until we have sent the key. */
tmp_len = strlen(channel->channel_key->cipher->name);
packet =
- silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN,
- id_string, tmp_len,
+ silc_channel_key_payload_encode(idp->len, idp->data,
+ strlen(channel->channel_key->
+ cipher->name),
channel->channel_key->cipher->name,
channel->key_len / 8, channel->key);
silc_server_packet_send(server, sock, SILC_PACKET_CHANNEL_KEY, 0,
packet->data, packet->len, FALSE);
+
silc_buffer_free(packet);
+ silc_buffer_free(idp);
}
- if (id_string)
- silc_free(id_string);
-
/* Finally, send notify message to all clients on the channel about
new user on the channel. */
if (!(cmd->packet->flags & SILC_PACKET_FLAG_FORWARDED)) {
if (!cmd->pending) {
- SilcBuffer channel_idp, client_idp;
-
- channel_idp = silc_id_payload_encode(channel->id,
- SILC_ID_CHANNEL_LEN,
- SILC_ID_CHANNEL);
- client_idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT_LEN,
- SILC_ID_CLIENT);
+ SilcBuffer clidp;
+ clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+
silc_server_send_notify_to_channel(server, channel,
- SILC_NOTIFY_TYPE_JOIN, 6, FALSE,
- "%s (%s@%s) has joined channel %s",
- client_idp->data, client_idp->len,
- client->nickname,
- strlen(client->nickname),
- client->username,
- strlen(client->username),
- sock->hostname,
- strlen(sock->hostname),
- channel_idp->data, channel_idp->len,
- channel_name,
- strlen(channel_name));
-
- silc_buffer_free(client_idp);
- silc_buffer_free(channel_idp);
+ SILC_NOTIFY_TYPE_JOIN, 1,
+ clidp->data, clidp->len);
+
+ silc_buffer_free(clidp);
} else {
/* This is pending command request. Send the notify after we have
received the key for the channel from the router. */
{
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
- SilcSocketConnection sock = cmd->sock;
unsigned int argc;
char *motd;
int motd_len;
{
}
+/* Checks that client has rights to add or remove channel modes. If any
+ of the checks fails FALSE is returned. */
+
+int silc_server_check_cmode_rights(SilcChannelEntry channel,
+ SilcChannelClientEntry client,
+ unsigned int mode)
+{
+ int is_op = client->mode & SILC_CHANNEL_UMODE_CHANOP;
+ int is_fo = client->mode & SILC_CHANNEL_UMODE_CHANFO;
+
+ /* Check whether has rights to change anything */
+ if (!is_op && !is_fo)
+ return FALSE;
+
+ /* Check whether has rights to change everything */
+ if (is_op && is_fo)
+ return TRUE;
+
+ /* We know that client is channel operator, check that they are not
+ changing anything that requires channel founder rights. Rest of the
+ modes are available automatically for channel operator. */
+
+ if (mode & SILC_CHANNEL_MODE_PRIVKEY) {
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVATE) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ if (mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ if (mode & SILC_CHANNEL_MODE_CIPHER) {
+ if (is_op && !is_fo)
+ return FALSE;
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+ if (is_op && !is_fo)
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/* Server side command of CMODE. Changes channel mode */
+
SILC_SERVER_CMD_FUNC(cmode)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcSocketConnection sock = cmd->sock;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcChannelID *channel_id;
+ SilcClientID *client_id;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcBuffer packet, cidp;
+ unsigned char *tmp, *tmp_id, *tmp_mask;
+ unsigned int argc, mode_mask, tmp_len, tmp_len2;
+ int i;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ argc = silc_argument_get_arg_num(cmd->args);
+ if (argc < 2) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ if (argc > 8) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ goto out;
+ }
+
+ /* Get Channel ID */
+ tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len2);
+ if (!tmp_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ channel_id = silc_id_payload_parse_id(tmp_id, tmp_len2);
+
+ /* Get the channel mode mask */
+ tmp_mask = silc_argument_get_arg_type(cmd->args, 2, &tmp_len);
+ if (!tmp_mask) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ SILC_GET32_MSB(mode_mask, tmp_mask);
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+
+ /* Check whether this client is on the channel */
+ if (!silc_server_client_on_channel(client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Get entry to the channel user list */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+ if (chl->client == client)
+ break;
+
+ /* Check that client has rights to change any requested channel modes */
+ if (!silc_server_check_cmode_rights(channel, chl, mode_mask)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
+ /*
+ * Check the modes. Modes that requires nothing special operation are
+ * not checked here.
+ */
+
+ if (mode_mask & SILC_CHANNEL_MODE_PRIVKEY) {
+ /* Channel uses private keys to protect traffic. Client(s) has set the
+ key locally they want to use, server does not know that key. */
+ /* Nothing interesting to do here now */
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PRIVKEY) {
+ /* The mode is removed and we need to generate and distribute
+ new channel key. Clients are not using private channel keys
+ anymore after this. */
+ unsigned int key_len;
+ unsigned char channel_key[32];
+
+ /* XXX Duplicated code, make own function for this!! LEAVE uses this
+ as well */
+
+ /* Re-generate channel key */
+ key_len = channel->key_len / 8;
+ for (i = 0; i < key_len; i++)
+ channel_key[i] = silc_rng_get_byte(server->rng);
+ channel->channel_key->cipher->set_key(channel->channel_key->context,
+ channel_key, key_len);
+ memset(channel->key, 0, key_len);
+ silc_free(channel->key);
+ channel->key = silc_calloc(key_len, sizeof(*channel->key));
+ memcpy(channel->key, channel_key, key_len);
+ memset(channel_key, 0, sizeof(channel_key));
+
+ /* Encode channel key payload to be distributed on the channel */
+ packet =
+ silc_channel_key_payload_encode(tmp_len2, tmp_id,
+ strlen(channel->channel_key->
+ cipher->name),
+ channel->channel_key->cipher->name,
+ key_len, channel->key);
+
+ /* If we are normal server then we will send it to our router. If we
+ are router we will send it to all local servers that has clients on
+ the channel */
+ if (server->server_type == SILC_SERVER) {
+ if (!server->standalone)
+ silc_server_packet_send(server,
+ cmd->server->id_entry->router->connection,
+ SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+ packet->len, TRUE);
+ } else {
+
+ }
+
+ /* Send to locally connected clients on the channel */
+ silc_server_packet_send_local_channel(server, channel,
+ SILC_PACKET_CHANNEL_KEY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ }
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_ULIMIT) {
+ /* User limit is set on channel */
+ unsigned int user_limit;
+
+ /* Get user limit */
+ tmp = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ if (!tmp) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_ULIMIT)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ } else {
+ SILC_GET32_MSB(user_limit, tmp);
+ channel->mode_data.user_limit = user_limit;
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_ULIMIT)
+ /* User limit mode is unset. Remove user limit */
+ channel->mode_data.user_limit = 0;
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_PASSPHRASE) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_PASSPHRASE)) {
+ /* Passphrase has been set to channel */
+
+ /* Get the passphrase */
+ tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Save the passphrase */
+ channel->mode_data.passphrase = strdup(tmp);
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_PASSPHRASE) {
+ /* Passphrase mode is unset. remove the passphrase */
+ if (channel->mode_data.passphrase) {
+ silc_free(channel->mode_data.passphrase);
+ channel->mode_data.passphrase = NULL;
+ }
+ }
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_BAN) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_BAN)) {
+ /* Ban list is specified for channel */
+
+ /* Get ban list */
+ tmp = silc_argument_get_arg_type(cmd->args, 5, NULL);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* XXX check that channel founder is not banned */
+
+ /* Save the ban list */
+ channel->mode_data.ban_list = strdup(tmp);
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_BAN) {
+ /* Ban mode is unset. Remove the entire ban list */
+ if (channel->mode_data.ban_list) {
+ silc_free(channel->mode_data.ban_list);
+ channel->mode_data.ban_list = NULL;
+ }
+ }
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_INVITE_LIST) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_INVITE_LIST)) {
+ /* Invite list is specified for channel */
+
+ /* Get invite list */
+ tmp = silc_argument_get_arg_type(cmd->args, 6, NULL);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ /* Save the invite linst */
+ channel->mode_data.invite_list = strdup(tmp);
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_INVITE_LIST) {
+ /* Invite list mode is unset. Remove the entire invite list */
+ if (channel->mode_data.invite_list) {
+ silc_free(channel->mode_data.invite_list);
+ channel->mode_data.invite_list = NULL;
+ }
+ }
+ }
+
+ if (mode_mask & SILC_CHANNEL_MODE_CIPHER) {
+ if (!(channel->mode & SILC_CHANNEL_MODE_CIPHER)) {
+ /* Cipher to use protect the traffic */
+ unsigned int key_len = 128;
+ unsigned char channel_key[32];
+ char *cp;
+
+ /* Get cipher */
+ tmp = silc_argument_get_arg_type(cmd->args, 8, NULL);
+ if (!tmp) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+
+ cp = strchr(tmp, ':');
+ if (cp) {
+ key_len = atoi(cp);
+ *cp = '\0';
+ }
+
+ /* XXX Duplicated code, make own function for this!! */
+
+ /* Delete old cipher and allocate the new one */
+ silc_cipher_free(channel->channel_key);
+ silc_cipher_alloc(tmp, &channel->channel_key);
+
+ /* Re-generate channel key */
+ key_len /= 8;
+ if (key_len > sizeof(channel_key))
+ key_len = sizeof(channel_key);
+
+ for (i = 0; i < key_len; i++)
+ channel_key[i] = silc_rng_get_byte(server->rng);
+ channel->channel_key->cipher->set_key(channel->channel_key->context,
+ channel_key, key_len);
+ memset(channel->key, 0, key_len);
+ silc_free(channel->key);
+ channel->key = silc_calloc(key_len, sizeof(*channel->key));
+ memcpy(channel->key, channel_key, key_len);
+ memset(channel_key, 0, sizeof(channel_key));
+
+ /* Encode channel key payload to be distributed on the channel */
+ packet =
+ silc_channel_key_payload_encode(tmp_len2, tmp_id,
+ strlen(channel->channel_key->
+ cipher->name),
+ channel->channel_key->cipher->name,
+ key_len, channel->key);
+
+ /* If we are normal server then we will send it to our router. If we
+ are router we will send it to all local servers that has clients on
+ the channel */
+ if (server->server_type == SILC_SERVER) {
+ if (!server->standalone)
+ silc_server_packet_send(server,
+ cmd->server->id_entry->router->connection,
+ SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+ packet->len, TRUE);
+ } else {
+
+ }
+
+ /* Send to locally connected clients on the channel */
+ silc_server_packet_send_local_channel(server, channel,
+ SILC_PACKET_CHANNEL_KEY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ }
+ } else {
+ if (channel->mode & SILC_CHANNEL_MODE_CIPHER) {
+ /* Cipher mode is unset. Remove the cipher and revert back to
+ default cipher */
+ unsigned int key_len;
+ unsigned char channel_key[32];
+
+ if (channel->mode_data.cipher) {
+ silc_free(channel->mode_data.cipher);
+ channel->mode_data.cipher = NULL;
+ channel->mode_data.key_len = 0;
+ }
+
+ /* Generate new cipher and key for the channel */
+
+ /* XXX Duplicated code, make own function for this!! */
+
+ /* Delete old cipher and allocate default one */
+ silc_cipher_free(channel->channel_key);
+ if (!channel->cipher)
+ silc_cipher_alloc("twofish", &channel->channel_key);
+ else
+ silc_cipher_alloc(channel->cipher, &channel->channel_key);
+
+ /* Re-generate channel key */
+ key_len = channel->key_len / 8;
+ for (i = 0; i < key_len; i++)
+ channel_key[i] = silc_rng_get_byte(server->rng);
+ channel->channel_key->cipher->set_key(channel->channel_key->context,
+ channel_key, key_len);
+ memset(channel->key, 0, key_len);
+ silc_free(channel->key);
+ channel->key = silc_calloc(key_len, sizeof(*channel->key));
+ memcpy(channel->key, channel_key, key_len);
+ memset(channel_key, 0, sizeof(channel_key));
+
+ /* Encode channel key payload to be distributed on the channel */
+ packet =
+ silc_channel_key_payload_encode(tmp_len2, tmp_id,
+ strlen(channel->channel_key->
+ cipher->name),
+ channel->channel_key->cipher->name,
+ key_len, channel->key);
+
+ /* If we are normal server then we will send it to our router. If we
+ are router we will send it to all local servers that has clients on
+ the channel */
+ if (server->server_type == SILC_SERVER) {
+ if (!server->standalone)
+ silc_server_packet_send(server,
+ cmd->server->id_entry->router->connection,
+ SILC_PACKET_CHANNEL_KEY, 0, packet->data,
+ packet->len, TRUE);
+ } else {
+
+ }
+
+ /* Send to locally connected clients on the channel */
+ silc_server_packet_send_local_channel(server, channel,
+ SILC_PACKET_CHANNEL_KEY, 0,
+ packet->data, packet->len, FALSE);
+ silc_buffer_free(packet);
+ }
+ }
+
+ /* Finally, set the mode */
+ channel->mode = mode_mask;
+
+ /* Send CMODE_CHANGE notify */
+ cidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ silc_server_send_notify_to_channel(server, channel,
+ SILC_NOTIFY_TYPE_CMODE_CHANGE, 2,
+ cidp->data, cidp->len,
+ tmp_mask, tmp_len);
+ silc_free(cidp);
+
+ /* Send command reply to sender */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CMODE,
+ SILC_STATUS_OK, 0, 1,
+ 2, tmp_mask, 4);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_free(channel_id);
+
+ out:
+ silc_server_command_free(cmd);
+}
+
+/* Server side of CUMODE command. Changes client's mode on a channel. */
+
+SILC_SERVER_CMD_FUNC(cumode)
+{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcSocketConnection sock = cmd->sock;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+ SilcChannelID *channel_id;
+ SilcClientID *client_id;
+ SilcChannelEntry channel;
+ SilcClientEntry target_client;
+ SilcChannelClientEntry chl;
+ SilcBuffer packet, idp;
+ unsigned char *tmp, *tmp_id, *tmp_mask;
+ unsigned int argc, target_mask, sender_mask, tmp_len;
+ int i, notify = FALSE;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ argc = silc_argument_get_arg_num(cmd->args);
+ if (argc < 3) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ if (argc > 3) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_TOO_MANY_PARAMS);
+ goto out;
+ }
+
+ /* Get Channel ID */
+ tmp_id = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
+ if (!tmp_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ channel_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+
+ /* Get channel entry */
+ channel = silc_idlist_find_channel_by_id(server->local_list, channel_id);
+ if (!channel) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL);
+ goto out;
+ }
+
+ /* Check whether sender is on the channel */
+ if (!silc_server_client_on_channel(client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Check that client has rights to change other's rights */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ if (chl->client == client) {
+ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANFO) &&
+ !(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV);
+ goto out;
+ }
+
+ sender_mask = chl->mode;
+ break;
+ }
+ }
+
+ /* Get the target client's channel mode mask */
+ tmp_mask = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (!tmp_mask) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS);
+ goto out;
+ }
+ SILC_GET32_MSB(target_mask, tmp_mask);
+
+ /* Get target Client ID */
+ tmp_id = silc_argument_get_arg_type(cmd->args, 3, &tmp_len);
+ if (!tmp_id) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NO_CHANNEL_ID);
+ goto out;
+ }
+ client_id = silc_id_payload_parse_id(tmp_id, tmp_len);
+
+ /* Get target client's entry */
+ target_client = silc_idlist_find_client_by_id(server->local_list, client_id);
+ if (!client) {
+ /* XXX If target client is not one of mine send to primary route */
+ }
+
+ /* Check whether target client is on the channel */
+ if (!silc_server_client_on_channel(target_client, channel)) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_USER_NOT_ON_CHANNEL);
+ goto out;
+ }
+
+ /* Get entry to the channel user list */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END)
+ if (chl->client == target_client)
+ break;
+
+ /*
+ * Change the mode
+ */
+
+ /* If the target client is founder, no one else can change their mode
+ but themselves. */
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO && chl->client != target_client) {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ }
+
+ if (target_mask & SILC_CHANNEL_UMODE_CHANFO) {
+ /* Cannot promote anyone to channel founder */
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ } else {
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANFO) {
+ if (target_client == client) {
+ /* Remove channel founder rights from itself */
+ chl->mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ notify = TRUE;
+ } else {
+ silc_server_command_send_status_reply(cmd, SILC_COMMAND_CUMODE,
+ SILC_STATUS_ERR_NOT_YOU);
+ goto out;
+ }
+ }
+ }
+
+ if (target_mask & SILC_CHANNEL_UMODE_CHANOP) {
+ /* Promote to operator */
+ if (!(chl->mode & SILC_CHANNEL_UMODE_CHANOP)) {
+ chl->mode |= SILC_CHANNEL_UMODE_CHANOP;
+ notify = TRUE;
+ }
+ } else {
+ if (chl->mode & SILC_CHANNEL_UMODE_CHANOP) {
+ /* Demote to normal user */
+ chl->mode &= ~SILC_CHANNEL_UMODE_CHANOP;
+ notify = TRUE;
+ }
+ }
+
+ /* Send notify to channel, notify only if mode was actually changed. */
+ if (notify) {
+ idp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
+ silc_server_send_notify_to_channel(server, channel,
+ SILC_NOTIFY_TYPE_CUMODE_CHANGE, 3,
+ idp->data, idp->len,
+ tmp_mask, 4, tmp_id, tmp_len);
+ silc_buffer_free(idp);
+ }
+
+ /* Send command reply to sender */
+ packet = silc_command_reply_payload_encode_va(SILC_COMMAND_CUMODE,
+ SILC_STATUS_OK, 0, 2,
+ 2, tmp_mask, 4,
+ 3, tmp_id, tmp_len);
+ silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
+ packet->data, packet->len, FALSE);
+
+ silc_buffer_free(packet);
+ silc_free(channel_id);
+ silc_free(client_id);
+
+ out:
+ silc_server_command_free(cmd);
}
+/* Server side of KICK command. Kicks client out of channel. */
+
SILC_SERVER_CMD_FUNC(kick)
{
+ SilcServerCommandContext cmd = (SilcServerCommandContext)context;
+ SilcServer server = cmd->server;
+ SilcSocketConnection sock = cmd->sock;
+ SilcClientEntry client = (SilcClientEntry)cmd->sock->user_data;
+
}
SILC_SERVER_CMD_FUNC(restart)
SilcChannelID *id;
SilcChannelEntry channel;
SilcBuffer packet;
- unsigned int i, argc, key_len;
+ unsigned int i, argc, key_len, len;
unsigned char *tmp, channel_key[32];
SILC_LOG_DEBUG(("Start"));
}
/* Get Channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &len);
if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
SILC_STATUS_ERR_NO_CHANNEL_ID);
goto out;
}
- id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+ id = silc_id_payload_parse_id(tmp, len);
/* Get channel entry */
channel = silc_idlist_find_channel_by_id(server->local_list, id);
/* Encode channel key payload to be distributed on the channel */
packet =
- silc_channel_key_payload_encode(SILC_ID_CHANNEL_LEN, tmp,
+ silc_channel_key_payload_encode(len, tmp,
strlen(channel->channel_key->cipher->name),
channel->channel_key->cipher->name,
key_len, channel->key);
SilcServerCommandContext cmd = (SilcServerCommandContext)context;
SilcServer server = cmd->server;
SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
SilcChannelID *id;
SilcBuffer packet;
- unsigned int i, len, len2, argc;
+ unsigned int i, len, len2, tmp_len, argc;
unsigned char *tmp;
char *name_list = NULL, *n;
SilcBuffer client_id_list;
+ SilcBuffer client_mode_list;
SILC_LOG_DEBUG(("Start"));
}
/* Get Channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
+ tmp = silc_argument_get_arg_type(cmd->args, 1, &tmp_len);
if (!tmp) {
silc_server_command_send_status_reply(cmd, SILC_COMMAND_LEAVE,
SILC_STATUS_ERR_NO_CHANNEL_ID);
goto out;
}
- id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+ id = silc_id_payload_parse_id(tmp, tmp_len);
/* Check whether the channel exists. If we are normal server and the
channel does not exist we will send this same command to our router
/* Assemble the name list now */
name_list = NULL;
len = 0;
- for (i = 0; i < channel->user_list_count; i++) {
- if (!channel->user_list[i].client)
- continue;
-
- n = channel->user_list[i].client->nickname;
+ silc_list_start(channel->user_list);
+ i = 0;
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ n = chl->client->nickname;
if (n) {
len2 = strlen(n);
len += len2;
memcpy(name_list + (len - len2), n, len2);
name_list[len] = 0;
- if (i == channel->user_list_count - 1)
+ if (i == silc_list_count(channel->user_list) - 1)
break;
memcpy(name_list + len, ",", 1);
len++;
+ i++;
}
}
if (!name_list)
name_list = "";
/* Assemble the Client ID list now */
- client_id_list = silc_buffer_alloc(SILC_ID_CLIENT_LEN *
- channel->user_list_count);
- silc_buffer_pull_tail(client_id_list, (SILC_ID_CLIENT_LEN *
- channel->user_list_count));
- for (i = 0; i < channel->user_list_count; i++) {
- unsigned char *id_string;
-
- if (!channel->user_list[i].client)
- continue;
-
- id_string = silc_id_id2str(channel->user_list[i].client->id,
- SILC_ID_CLIENT);
+ client_id_list = silc_buffer_alloc((SILC_ID_CLIENT_LEN + 4) *
+ silc_list_count(channel->user_list));
+ silc_buffer_pull_tail(client_id_list, SILC_BUFFER_END(client_id_list));
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ SilcBuffer idp;
+
+ idp = silc_id_payload_encode(chl->client->id, SILC_ID_CLIENT);
silc_buffer_format(client_id_list,
- SILC_STR_UI_XNSTRING(id_string, SILC_ID_CLIENT_LEN),
+ SILC_STR_UI_XNSTRING(idp->data, idp->len),
SILC_STR_END);
- silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
- silc_free(id_string);
+ silc_buffer_pull(client_id_list, idp->len);
+ silc_buffer_free(idp);
}
silc_buffer_push(client_id_list,
client_id_list->data - client_id_list->head);
+ /* Assemble mode list */
+ client_mode_list = silc_buffer_alloc(4 *
+ silc_list_count(channel->user_list));
+ silc_buffer_pull_tail(client_mode_list, SILC_BUFFER_END(client_mode_list));
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ SILC_PUT32_MSB(chl->mode, client_mode_list->data);
+ silc_buffer_pull(client_mode_list, 4);
+ }
+ silc_buffer_push(client_mode_list,
+ client_mode_list->data - client_mode_list->head);
+
/* Send reply */
packet = silc_command_reply_payload_encode_va(SILC_COMMAND_NAMES,
- SILC_STATUS_OK, 0, 3,
- 2, tmp, SILC_ID_CHANNEL_LEN,
+ SILC_STATUS_OK, 0, 4,
+ 2, tmp, tmp_len,
3, name_list,
strlen(name_list),
4, client_id_list->data,
- client_id_list->len);
+ client_id_list->len,
+ 5, client_mode_list->data,
+ client_mode_list->len);
silc_server_packet_send(server, cmd->sock, SILC_PACKET_COMMAND_REPLY, 0,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
silc_free(name_list);
silc_buffer_free(client_id_list);
+ silc_buffer_free(client_mode_list);
silc_free(id);
out:
SILC_SERVER_CMD_FUNC(motd);
SILC_SERVER_CMD_FUNC(umode);
SILC_SERVER_CMD_FUNC(cmode);
+SILC_SERVER_CMD_FUNC(cumode);
SILC_SERVER_CMD_FUNC(kick);
SILC_SERVER_CMD_FUNC(ignore);
SILC_SERVER_CMD_FUNC(restart);
SilcCommandStatus status;
SilcChannelID *id;
SilcChannelEntry entry;
+ unsigned int len;
unsigned char *id_string;
char *channel_name, *tmp;
goto out;
/* Get channel ID */
- id_string = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ id_string = silc_argument_get_arg_type(cmd->args, 3, &len);
if (!id_string)
goto out;
channel_name = strdup(tmp);
/* Add the channel to our local list. */
- id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+ id = silc_id_payload_parse_id(id_string, len);
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, id,
server->id_entry->router, NULL);
- if (!entry)
+ if (!entry) {
+ silc_free(channel_name);
+ silc_free(id);
goto out;
+ }
entry->global_users = TRUE;
SilcServerCommandReplyContext cmd = (SilcServerCommandReplyContext)context;
SilcServer server = cmd->server;
SilcCommandStatus status;
- unsigned char *tmp;
SILC_LOG_DEBUG(("Start"));
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
- SILC_GET16_MSB(status, tmp);
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK)
goto out;
/* Process one identify reply */
if (status == SILC_STATUS_OK) {
SilcClientID *client_id;
+ unsigned int len;
unsigned char *id_data;
char *nickname, *username;
- id_data = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
if (!id_data || !nickname)
goto out;
username = silc_argument_get_arg_type(cmd->args, 4, NULL);
-
- client_id = silc_id_str2id(id_data, SILC_ID_CLIENT);
+ client_id = silc_id_payload_parse_id(id_data, len);
/* Add the client always to our global list. If normal or router server
ever gets here it means they don't have this client's information
GNU General Public License for more details.
*/
-/*
- * $Id$
- * $Log$
- * Revision 1.8 2000/10/06 08:10:23 priikone
- * Added WHOIS to send multiple replies if multiple nicknames are
- * found.
- * Added MOTD command and [motd] config section and server also sends
- * motd to client on connection now.
- * Fixed TOPIC command some more.
- *
- * Revision 1.7 2000/07/26 07:04:01 priikone
- * Added server_find_by_id, replace_[server/client]_id.
- *
- * Revision 1.6 2000/07/17 11:47:30 priikone
- * Added command lagging support. Added idle counting support.
- *
- * Revision 1.5 2000/07/12 05:59:41 priikone
- * Major rewrite of ID Cache system. Support added for the new
- * ID cache system. Major rewrite of ID List stuff on server. All
- * SilcXXXList's are now called SilcXXXEntry's and they are pointers
- * by default. A lot rewritten ID list functions.
- *
- * Revision 1.4 2000/07/06 07:16:13 priikone
- * Added SilcPublicKey's
- *
- * Revision 1.3 2000/07/05 06:14:01 priikone
- * Global costemic changes.
- *
- * Revision 1.2 2000/07/03 05:52:11 priikone
- * Fixed typo and a bug.
- *
- * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
- * Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
#include "serverincludes.h"
#include "idlist.h"
channel->id = id;
channel->router = router;
channel->channel_key = channel_key;
+ silc_list_init(channel->user_list, struct SilcChannelClientEntryStruct,
+ next);
if (!silc_idcache_add(id_list->channels, channel->channel_name,
SILC_ID_CHANNEL, (void *)channel->id,
void silc_idlist_del_channel(SilcIDList id_list, SilcChannelEntry entry)
{
if (entry) {
+ SilcChannelClientEntry chl;
+
/* Remove from cache */
if (entry->id)
silc_idcache_del_by_id(id_list->channels, SILC_ID_CHANNEL,
silc_free(entry->key);
}
memset(entry->iv, 0, sizeof(entry->iv));
-
- if (entry->user_list_count)
- silc_free(entry->user_list);
+
+ silc_list_start(entry->user_list);
+ while ((chl = silc_list_get(entry->user_list)) != SILC_LIST_END) {
+ silc_list_del(entry->user_list, chl);
+ silc_free(chl);
+ }
}
}
/* Pointer to the router */
SilcServerEntry router;
- /* Pointers to channels this client has joined */
+ /* List of channels client has joined to */
SilcChannelEntry *channel;
unsigned int channel_count;
Pointer to the client list. This is the client currently on channel.
- int mode
+ unsigned int mode
Client's current mode on the channel.
*/
typedef struct SilcChannelClientEntryStruct {
SilcClientEntry client;
- int mode;
+ unsigned int mode;
+ struct SilcChannelClientEntryStruct *next;
} *SilcChannelClientEntry;
/*
Logical name of the channel.
- int mode
+ unsigned int mode
- Current mode of the channel.
+ Current mode of the channel. See lib/silccore/silcchannel.h for
+ all modes.
SilcChannelID *id
Current topic of the channel.
+ char *cipher
+
+ Default cipher of the channel. If this is NULL then server picks
+ the cipher to be used. This can be set at SILC_COMMAND_JOIN.
+
SilcServerEntry router
This is a pointer to the server list. This is the router server
*/
struct SilcChannelEntryStruct {
char *channel_name;
- int mode;
+ unsigned int mode;
SilcChannelID *id;
int global_users;
char *topic;
+ char *cipher;
+
+ /* Data that is related to different channel modes. */
+ struct {
+ unsigned int user_limit;
+ unsigned char *passphrase;
+ unsigned char *ban_list;
+ unsigned char *invite_list;
+ unsigned char *cipher;
+ unsigned int key_len;
+ } mode_data;
/* List of users on channel */
- SilcChannelClientEntry user_list;
- unsigned int user_list_count;
+ SilcList user_list;
/* Pointer to the router */
SilcServerEntry router;
/*
* Server side of the protocols.
*/
-/*
- * $Id$
- * $Log$
- * Revision 1.10 2000/10/09 11:41:17 priikone
- * Changed to use new generic payloads.
- * Implemented new protocol compliant notify messages.
- * Implemented protocol compliant channel messages.
- * Bugfixes.
- *
- * Revision 1.9 2000/07/20 10:17:25 priikone
- * Added dynamic protocol registering/unregistering support. The
- * patch was provided by cras.
- *
- * Revision 1.8 2000/07/19 07:08:09 priikone
- * Added version detection support to SKE.
- *
- * Revision 1.7 2000/07/14 06:14:20 priikone
- * Put the HMAC keys into the HMAC object instead of having them
- * saved elsewhere; now we can use silc_hmac_make insteaad of
- * silc_hmac_make_with_key.
- *
- * Revision 1.6 2000/07/12 05:59:41 priikone
- * Major rewrite of ID Cache system. Support added for the new
- * ID cache system. Major rewrite of ID List stuff on server. All
- * SilcXXXList's are now called SilcXXXEntry's and they are pointers
- * by default. A lot rewritten ID list functions.
- *
- * Revision 1.5 2000/07/10 05:42:14 priikone
- * Support for public key encoding functions added.
- *
- * Revision 1.4 2000/07/07 06:55:59 priikone
- * Added SILC style public key support and made server to use
- * it at all time.
- *
- * Revision 1.3 2000/07/06 07:15:31 priikone
- * Cleaner code fro password and public key authentication.
- * Deprecated old `channel_auth' protocol.
- *
- * Revision 1.2 2000/07/05 06:13:04 priikone
- * Support for SILC style public keys added.
- *
- * Revision 1.1.1.1 2000/06/27 11:36:56 priikone
- * Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
#include "serverincludes.h"
#include "server_internal.h"
sock->user_data = (void *)conn_data;
}
+/* XXX TODO */
+
+SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
+ unsigned int len)
+{
+ return SILC_SKE_STATUS_OK;
+}
+
/* Performs key exchange protocol. This is used for both initiator
and responder key exchange. This is performed always when accepting
new connection to the server. This may be called recursively. */
protocol->state = SILC_PROTOCOL_STATE_END;
}
break;
+
case SILC_PROTOCOL_STATE_END:
{
/*
silc_protocol_free(protocol);
}
break;
+
case SILC_PROTOCOL_STATE_ERROR:
/*
* Error occured
*/
+ /* Send abort notification */
+ silc_ske_abort(ctx->ske, ctx->ske->status,
+ silc_server_protocol_ke_send_packet,
+ context);
+
/* Unregister the timeout task since the protocol has ended.
This was the timeout task to be executed if the protocol is
not completed fast enough. */
else
silc_protocol_free(protocol);
break;
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * We have received failure from remote
+ */
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+
case SILC_PROTOCOL_STATE_UNKNOWN:
break;
}
/*
* End protocol
*/
+ unsigned char ok[4];
+
+ SILC_PUT32_MSB(SILC_CONN_AUTH_OK, ok);
- /* Succesfully authenticated */
- silc_server_packet_send(server, ctx->sock, SILC_PACKET_SUCCESS,
- 0, NULL, 0, TRUE);
+ /* Authentication failed */
+ silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
+ 0, ok, 4, TRUE);
/* Unregister the timeout task since the protocol has ended.
This was the timeout task to be executed if the protocol is
case SILC_PROTOCOL_STATE_ERROR:
{
/*
- * Error
+ * Error. Send notify to remote.
*/
+ unsigned char error[4];
+
+ SILC_PUT32_MSB(SILC_CONN_AUTH_FAILED, error);
/* Authentication failed */
silc_server_packet_send(server, ctx->sock, SILC_PACKET_FAILURE,
- 0, NULL, 0, TRUE);
+ 0, error, 4, TRUE);
/* Unregister the timeout task since the protocol has ended.
This was the timeout task to be executed if the protocol is
silc_protocol_free(protocol);
}
break;
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * We have received failure from remote
+ */
+
+ /* Unregister the timeout task since the protocol has ended.
+ This was the timeout task to be executed if the protocol is
+ not completed fast enough. */
+ if (ctx->timeout_task)
+ silc_task_unregister(server->timeout_queue, ctx->timeout_task);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(server->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+
case SILC_PROTOCOL_STATE_UNKNOWN:
break;
}
out:
silc_buffer_clear(sock->inbuf);
+ if (packet->src_id)
+ silc_free(packet->src_id);
+ if (packet->dst_id)
+ silc_free(packet->dst_id);
silc_free(packet);
silc_free(parse_ctx);
}
}
break;
case SILC_PACKET_FAILURE:
+ /*
+ * Failure received for something. For now we can have only
+ * one protocol for connection executing at once hence this
+ * failure message is for whatever protocol is executing currently.
+ */
SILC_LOG_DEBUG(("Failure packet"));
+ if (sock->protocol) {
+ /* XXX Audit the failure type */
+ sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
+ sock->protocol->execute(server->timeout_queue, 0,
+ sock->protocol, sock->sock, 0, 0);
+ }
break;
case SILC_PACKET_REJECT:
SILC_LOG_DEBUG(("Reject packet"));
}
/* Internal routine to actually create the channel packet and send it
- to network. This is common function in channel message sending. */
+ to network. This is common function in channel message sending. If
+ `channel_message' is TRUE this encrypts the message as it is strictly
+ a channel message. If FALSE normal encryption process is used. */
static void
silc_server_packet_send_to_channel_real(SilcServer server,
SilcPacketContext packetdata;
SilcClientEntry client = NULL;
SilcServerEntry *routed = NULL;
+ SilcChannelClientEntry chl;
unsigned int routed_count = 0;
SilcCipher cipher;
SilcHmac hmac;
}
/* Send the message to clients on the channel's client list. */
- for (i = 0; i < channel->user_list_count; i++) {
- client = channel->user_list[i].client;
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ client = chl->client;
/* If client has router set it is not locally connected client and
we will route the message to the router set in the client. */
/* Check if we have sent the packet to this route already */
for (k = 0; k < routed_count; k++)
if (routed[k] == client->router)
- continue;
+ break;
+ if (k < routed_count)
+ continue;
/* Get data used in packet header encryption, keys and stuff. */
sock = (SilcSocketConnection)client->router->connection;
SilcPacketContext packetdata;
SilcClientEntry client = NULL;
SilcServerEntry *routed = NULL;
+ SilcChannelClientEntry chl;
unsigned int routed_count = 0;
SilcCipher cipher;
SilcHmac hmac;
}
/* Send the message to clients on the channel's client list. */
- for (i = 0; i < channel->user_list_count; i++) {
- client = channel->user_list[i].client;
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ client = chl->client;
if (client) {
/* Check if we have sent the packet to this route already */
for (k = 0; k < routed_count; k++)
if (routed[k] == client->router)
- continue;
+ break;
+ if (k < routed_count)
+ continue;
/* Get data used in packet header encryption, keys and stuff. */
sock = (SilcSocketConnection)client->router->connection;
on a particular channel. This is used for example to distribute new
channel key to all our locally connected clients on the channel.
The packets are always encrypted with the session key shared between
- the client. */
+ the client, this means these are not _to the channel_ but _to the client_
+ on the channel. */
void silc_server_packet_send_local_channel(SilcServer server,
SilcChannelEntry channel,
{
int i;
SilcClientEntry client;
+ SilcChannelClientEntry chl;
SilcSocketConnection sock = NULL;
SILC_LOG_DEBUG(("Start"));
/* Send the message to clients on the channel's client list. */
- for (i = 0; i < channel->user_list_count; i++) {
- client = channel->user_list[i].client;
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ client = chl->client;
if (client) {
sock = (SilcSocketConnection)client->connection;
{
int i, k;
SilcChannelEntry channel;
- SilcBuffer id_payload;
+ SilcChannelClientEntry chl;
+ SilcBuffer chidp, clidp;
+
+ SILC_LOG_DEBUG(("Start"));
+
+ clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Remove the client from all channels. The client is removed from
the channels' user list. */
if (!channel)
continue;
- id_payload = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL_LEN,
- SILC_ID_CHANNEL);
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
/* Remove from channel */
- for (k = 0; k < channel->user_list_count; k++) {
- if (channel->user_list[k].client == client) {
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ if (chl->client == client) {
/* If this client is last one on the channel the channel
is removed all together. */
- if (channel->user_list_count == 1) {
+ if (silc_list_count(channel->user_list) == 1) {
/* However, if the channel has marked global users then the
channel is not created locally, and this does not remove the
notify that this client has left the channel. */
if (channel->global_users)
silc_server_send_notify_to_channel(server, channel,
- SILC_NOTIFY_TYPE_SIGNOFF, 3,
- FALSE,
- "Signoff: %s@%s",
- client->nickname,
- strlen(client->nickname),
- sock->hostname,
- strlen(sock->hostname),
- id_payload->data,
- id_payload->len);
+ SILC_NOTIFY_TYPE_SIGNOFF, 1,
+ clidp->data, clidp->len);
silc_idlist_del_channel(server->local_list, channel);
break;
}
- channel->user_list[k].client = NULL;
- channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
+ silc_list_del(channel->user_list, chl);
+ silc_free(chl);
/* Send notify to channel about client leaving SILC and thus
the entire channel. */
silc_server_send_notify_to_channel(server, channel,
- SILC_NOTIFY_TYPE_SIGNOFF, 3,
- FALSE,
- "Signoff: %s@%s",
- client->nickname,
- strlen(client->nickname),
- sock->hostname,
- strlen(sock->hostname),
- id_payload->data,
- id_payload->len);
+ SILC_NOTIFY_TYPE_SIGNOFF, 1,
+ clidp->data, clidp->len);
}
}
- silc_free(id_payload);
+ silc_buffer_free(chidp);
}
if (client->channel_count)
silc_free(client->channel);
client->channel = NULL;
+ silc_buffer_free(clidp);
}
/* Removes client from one channel. This is used for example when client
{
int i, k;
SilcChannelEntry ch;
- SilcBuffer id_payload;
+ SilcChannelClientEntry chl;
+ SilcBuffer clidp;
+
+ SILC_LOG_DEBUG(("Start"));
- id_payload = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL_LEN,
- SILC_ID_CHANNEL);
+ clidp = silc_id_payload_encode(client->id, SILC_ID_CLIENT);
/* Remove the client from the channel. The client is removed from
the channel's user list. */
if (!ch || ch != channel)
continue;
- /* XXX */
client->channel[i] = NULL;
/* Remove from channel */
- for (k = 0; k < channel->user_list_count; k++) {
- if (channel->user_list[k].client == client) {
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ if (chl->client == client) {
/* If this client is last one on the channel the channel
is removed all together. */
- if (channel->user_list_count == 1) {
+ if (silc_list_count(channel->user_list) == 1) {
/* Notify about leaving client if this channel has global users,
ie. the channel is not created locally. */
if (notify && channel->global_users)
silc_server_send_notify_to_channel(server, channel,
- SILC_NOTIFY_TYPE_LEAVE, 4,
- FALSE,
- "%s@%s has left channel %s",
- client->nickname,
- strlen(client->nickname),
- sock->hostname,
- strlen(sock->hostname),
- id_payload->data,
- id_payload->len,
- channel->channel_name,
- strlen(channel->channel_name));
+ SILC_NOTIFY_TYPE_LEAVE, 1,
+ clidp->data, clidp->len);
silc_idlist_del_channel(server->local_list, channel);
- silc_buffer_free(id_payload);
+ silc_buffer_free(clidp);
return FALSE;
}
- channel->user_list[k].client = NULL;
- channel->user_list[k].mode = SILC_CHANNEL_UMODE_NONE;
+ silc_list_del(channel->user_list, chl);
+ silc_free(chl);
/* Send notify to channel about client leaving the channel */
if (notify)
silc_server_send_notify_to_channel(server, channel,
- SILC_NOTIFY_TYPE_LEAVE, 4,
- FALSE,
- "%s@%s has left channel %s",
- client->nickname,
- strlen(client->nickname),
- sock->hostname,
- strlen(sock->hostname),
- id_payload->data,
- id_payload->len,
- channel->channel_name,
- strlen(channel->channel_name));
+ SILC_NOTIFY_TYPE_LEAVE, 1,
+ clidp->data, clidp->len);
}
}
}
- silc_buffer_free(id_payload);
+ silc_buffer_free(clidp);
return TRUE;
}
This works because we assure that the user list on the channel is
always in up to date thus we can only check the channel list from
`client' which is faster than checking the user list from `channel'. */
-/* XXX This really is utility function and should be in eg. serverutil.c */
int silc_server_client_on_channel(SilcClientEntry client,
SilcChannelEntry channel)
SilcPacketContext *packet)
{
SilcChannelEntry channel = NULL;
+ SilcChannelClientEntry chl;
SilcClientEntry client = NULL;
SilcChannelID *id = NULL;
void *sender = NULL;
sender = silc_id_str2id(packet->src_id, packet->src_id_type);
if (sock->type != SILC_SOCKET_TYPE_ROUTER &&
packet->src_id_type == SILC_ID_CLIENT) {
- for (i = 0; i < channel->user_list_count; i++) {
- client = channel->user_list[i].client;
- if (client && !SILC_ID_CLIENT_COMPARE(client->id, sender))
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ if (chl->client && !SILC_ID_CLIENT_COMPARE(chl->client->id, sender))
break;
}
- if (i >= channel->user_list_count)
+ if (chl == SILC_LIST_END)
goto out;
}
SilcChannelKeyPayload payload = NULL;
SilcChannelID *id = NULL;
SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
SilcClientEntry client;
- unsigned char *key;
- unsigned int key_len;
+ unsigned char *tmp;
+ unsigned int tmp_len;
char *cipher;
int i;
}
/* Get channel ID */
- id = silc_id_str2id(silc_channel_key_get_id(payload, NULL), SILC_ID_CHANNEL);
+ tmp = silc_channel_key_get_id(payload, &tmp_len);
+ id = silc_id_payload_parse_id(tmp, tmp_len);
if (!id)
goto out;
}
/* Save the key for us as well */
- key = silc_channel_key_get_key(payload, &key_len);
- if (!key)
+ tmp = silc_channel_key_get_key(payload, &tmp_len);
+ if (!tmp)
goto out;
cipher = silc_channel_key_get_cipher(payload, NULL);;
if (!cipher)
goto out;
- channel->key_len = key_len * 8;
- channel->key = silc_calloc(key_len, sizeof(unsigned char));
- memcpy(channel->key, key, key_len);
- silc_cipher_alloc(cipher, &channel->channel_key);
+ if (!silc_cipher_alloc(cipher, &channel->channel_key))
+ goto out;
+
+ channel->key_len = tmp_len * 8;
+ channel->key = silc_calloc(tmp_len, sizeof(unsigned char));
+ memcpy(channel->key, tmp, tmp_len);
channel->channel_key->cipher->set_key(channel->channel_key->context,
- key, key_len);
+ tmp, tmp_len);
/* Distribute the key to all clients on the channel */
- for (i = 0; i < channel->user_list_count; i++) {
- client = channel->user_list[i].client;
+ /* XXX Some other sender should be used, I think this is not correct */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ client = chl->client;
if (client)
silc_server_packet_send_dest(server, client->connection,
void silc_server_send_motd(SilcServer server,
SilcSocketConnection sock)
{
- char *motd, *cp;
- char line[256];
- int i, motd_len;
+ char *motd;
+ int motd_len;
if (server->config && server->config->motd &&
server->config->motd->motd_file) {
if (!motd)
return;
- /* Send motd */
- i = 0;
- cp = motd;
- while(cp[i] != 0) {
- if (cp[i++] == '\n') {
- memset(line, 0, sizeof(line));
- strncat(line, cp, i - 1);
- cp += i;
-
- if (i == 1)
- line[0] = ' ';
-
- silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_NONE,
- 0, FALSE, line);
-
- if (!strlen(cp))
- break;
- i = 0;
- }
- }
-
+ silc_server_send_notify(server, sock, SILC_NOTIFY_TYPE_MOTD, 1,
+ motd, motd_len);
silc_free(motd);
}
}
buf, strlen(buf), FALSE);
}
-/* Sends notify message. If `format' is TRUE then the message and the
- arguments sent are formatted and that message is sent to the other
- end, if FALSE then arguments are encoded into argument payloads and
- the message is sent as is. */
+/* Sends notify message. If format is TRUE the variable arguments are
+ formatted and the formatted string is sent as argument payload. If it is
+ FALSE then each argument is sent as separate argument and their format
+ in the argument list must be { argument data, argument length }. */
void silc_server_send_notify(SilcServer server,
SilcSocketConnection sock,
SilcNotifyType type,
- unsigned int argc,
- unsigned int format,
- const char *fmt, ...)
+ unsigned int argc, ...)
{
va_list ap;
- char *cp;
- unsigned char buf[4096];
SilcBuffer packet;
- cp = (char *)fmt;
-
- if (argc)
- va_start(ap, fmt);
+ va_start(ap, argc);
- if (format && argc) {
- memset(buf, 0, sizeof(buf));
- vsprintf(buf, fmt, ap);
- va_end(ap);
- argc = 0;
- cp = buf;
- }
-
- packet = silc_notify_payload_encode(type, cp, argc, ap);
+ packet = silc_notify_payload_encode(type, argc, ap);
silc_server_packet_send(server, sock, SILC_PACKET_NOTIFY, 0,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
void *dest_id,
SilcIdType dest_id_type,
SilcNotifyType type,
- unsigned int argc,
- unsigned int format,
- const char *fmt, ...)
+ unsigned int argc, ...)
{
va_list ap;
- char *cp;
- unsigned char buf[4096];
SilcBuffer packet;
- cp = (char *)fmt;
-
- if (argc)
- va_start(ap, fmt);
+ va_start(ap, argc);
- if (format && argc) {
- memset(buf, 0, sizeof(buf));
- vsprintf(buf, fmt, ap);
- va_end(ap);
- argc = 0;
- cp = buf;
- }
-
- packet = silc_notify_payload_encode(type, cp, argc, ap);
+ packet = silc_notify_payload_encode(type, argc, ap);
silc_server_packet_send_dest(server, sock, SILC_PACKET_NOTIFY, 0,
dest_id, dest_id_type,
packet->data, packet->len, FALSE);
void silc_server_send_notify_to_channel(SilcServer server,
SilcChannelEntry channel,
SilcNotifyType type,
- unsigned int argc,
- unsigned int format,
- const char *fmt, ...)
+ unsigned int argc, ...)
{
va_list ap;
- char *cp;
- unsigned char buf[4096];
SilcBuffer packet;
- cp = (char *)fmt;
+ va_start(ap, argc);
- if (argc)
- va_start(ap, fmt);
-
- if (format && argc) {
- memset(buf, 0, sizeof(buf));
- vsprintf(buf, fmt, ap);
- va_end(ap);
- argc = 0;
- cp = buf;
- }
-
- packet = silc_notify_payload_encode(type, cp, argc, ap);
+ packet = silc_notify_payload_encode(type, argc, ap);
silc_server_packet_send_to_channel(server, channel,
SILC_PACKET_NOTIFY,
packet->data, packet->len, FALSE);
silc_buffer_free(packet);
}
+/* Send notify message to all clients the client has joined. It is quaranteed
+ that the message is sent only once to a client (ie. if a client is joined
+ on two same channel it will receive only one notify message). Also, this
+ sends only to local clients (locally connected if we are server, and to
+ local servers if we are router). */
+
+void silc_server_send_notify_on_channels(SilcServer server,
+ SilcClientEntry client,
+ SilcNotifyType type,
+ unsigned int argc, ...)
+{
+ int i, j, k;
+ SilcSocketConnection sock = NULL;
+ SilcPacketContext packetdata;
+ SilcClientEntry c;
+ SilcClientEntry *sent_clients = NULL;
+ unsigned int sent_clients_count = 0;
+ SilcServerEntry *routed = NULL;
+ unsigned int routed_count = 0;
+ SilcChannelEntry channel;
+ SilcChannelClientEntry chl;
+ SilcCipher cipher;
+ SilcHmac hmac;
+ SilcBuffer packet;
+ unsigned char *data;
+ unsigned int data_len;
+ int force_send = FALSE;
+ va_list ap;
+
+ if (!client->channel_count)
+ return;
+
+ va_start(ap, argc);
+ packet = silc_notify_payload_encode(type, argc, ap);
+ data = packet->data;
+ data_len = packet->len;
+
+ /* Set the packet context pointers. */
+ packetdata.flags = 0;
+ packetdata.type = SILC_PACKET_NOTIFY;
+ packetdata.src_id = silc_id_id2str(server->id, SILC_ID_SERVER);
+ packetdata.src_id_len = SILC_ID_SERVER_LEN;
+ packetdata.src_id_type = SILC_ID_SERVER;
+ packetdata.rng = server->rng;
+
+ for (i = 0; i < client->channel_count; i++) {
+ channel = client->channel[i];
+
+ /* Send the message to clients on the channel's client list. */
+ silc_list_start(channel->user_list);
+ while ((chl = silc_list_get(channel->user_list)) != SILC_LIST_END) {
+ c = chl->client;
+
+ /* Check if we have sent the packet to this client already */
+ for (k = 0; k < sent_clients_count; k++)
+ if (sent_clients[k] == c)
+ break;
+ if (k < sent_clients_count)
+ continue;
+
+ /* If we are router and if this client has router set it is not
+ locally connected client and we will route the message to the
+ router set in the client. */
+ if (c && c->router && server->server_type == SILC_ROUTER) {
+ /* Check if we have sent the packet to this route already */
+ for (k = 0; k < routed_count; k++)
+ if (routed[k] == c->router)
+ break;
+ if (k < routed_count)
+ continue;
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)c->router->connection;
+ cipher = c->router->send_key;
+ hmac = c->router->hmac;
+
+ packetdata.dst_id = silc_id_id2str(c->router->id, SILC_ID_SERVER);
+ packetdata.dst_id_len = SILC_ID_SERVER_LEN;
+ packetdata.dst_id_type = SILC_ID_SERVER;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ cipher, hmac, data,
+ data_len, FALSE, force_send);
+
+ silc_free(packetdata.dst_id);
+
+ /* We want to make sure that the packet is routed to same router
+ only once. Mark this route as sent route. */
+ k = routed_count;
+ routed = silc_realloc(routed, sizeof(*routed) * (k + 1));
+ routed[k] = c->router;
+ routed_count++;
+
+ continue;
+ }
+
+ /* Send to locally connected client */
+ if (c) {
+
+ /* Get data used in packet header encryption, keys and stuff. */
+ sock = (SilcSocketConnection)c->connection;
+ cipher = c->send_key;
+ hmac = c->hmac;
+
+ packetdata.dst_id = silc_id_id2str(c->id, SILC_ID_CLIENT);
+ packetdata.dst_id_len = SILC_ID_CLIENT_LEN;
+ packetdata.dst_id_type = SILC_ID_CLIENT;
+ packetdata.truelen = data_len + SILC_PACKET_HEADER_LEN +
+ packetdata.src_id_len + packetdata.dst_id_len;
+ packetdata.padlen = SILC_PACKET_PADLEN(packetdata.truelen);
+
+ /* Send the packet */
+ silc_server_packet_send_to_channel_real(server, sock, &packetdata,
+ cipher, hmac, data,
+ data_len, FALSE, force_send);
+
+ silc_free(packetdata.dst_id);
+
+ /* Make sure that we send the notify only once per client. */
+ sent_clients = silc_realloc(sent_clients, sizeof(*sent_clients) *
+ (sent_clients_count + 1));
+ sent_clients[sent_clients_count] = c;
+ sent_clients_count++;
+ }
+ }
+ }
+
+ if (routed_count)
+ silc_free(routed);
+ if (sent_clients_count)
+ silc_free(sent_clients);
+ silc_free(packetdata.src_id);
+}
+
/* Sends New ID Payload to remote end. The packet is used to distribute
information about new registered clients, servers, channel etc. usually
to routers so that they can keep these information up to date.
void *id, SilcIdType id_type,
unsigned int id_len)
{
- SilcBuffer packet;
- unsigned char *id_string;
-
- id_string = silc_id_id2str(id, id_type);
- if (!id_string)
- return;
-
- packet = silc_buffer_alloc(2 + 2 + id_len);
- silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
- silc_buffer_format(packet,
- SILC_STR_UI_SHORT(id_type),
- SILC_STR_UI_SHORT(id_len),
- SILC_STR_UI_XNSTRING(id_string, id_len),
- SILC_STR_END);
+ SilcBuffer idp;
+ idp = silc_id_payload_encode(id, id_type);
silc_server_packet_send(server, sock, SILC_PACKET_NEW_ID,
broadcast ? SILC_PACKET_FLAG_BROADCAST : 0,
- packet->data, packet->len, FALSE);
- silc_free(id_string);
- silc_buffer_free(packet);
+ idp->data, idp->len, FALSE);
+ silc_buffer_free(idp);
}
/* Sends Replace ID payload to remote end. This is used to replace old
silc_cipher_alloc(cipher, &key);
key->cipher->set_key(key->context, channel_key, key_len);
+ channel_name = strdup(channel_name);
+
/* Create the channel */
silc_id_create_channel_id(router_id, server->rng, &channel_id);
entry = silc_idlist_add_channel(server->local_list, channel_name,
SILC_CHANNEL_MODE_NONE, channel_id,
NULL, key);
- if (!entry)
+ if (!entry) {
+ silc_free(channel_name);
return NULL;
+ }
+#if 0
/* Add to cache */
silc_idcache_add(server->local_list->channels, channel_name,
SILC_ID_CHANNEL, channel_id, (void *)entry, TRUE);
+#endif
entry->key = silc_calloc(key_len, sizeof(*entry->key));
entry->key_len = key_len * 8;
reply->data, reply->len, FALSE);
silc_free(id_string);
silc_buffer_free(reply);
-
+
/* Send some nice info to the client */
- silc_server_send_notify(server, sock,
- SILC_NOTIFY_TYPE_NONE, 2, TRUE,
- "Welcome to the SILC Network %s@%s",
- username, sock->hostname);
- silc_server_send_notify(server, sock,
- SILC_NOTIFY_TYPE_NONE, 2, TRUE,
- "Your host is %s, running version %s",
- server->config->server_info->server_name,
- server_version);
- silc_server_send_notify(server, sock,
- SILC_NOTIFY_TYPE_NONE, 2, TRUE,
- "Your connection is secured with %s cipher, "
- "key length %d bits",
- client->send_key->cipher->name,
- client->send_key->cipher->key_len);
- silc_server_send_notify(server, sock,
- SILC_NOTIFY_TYPE_NONE, 1, TRUE,
- "Your current nickname is %s",
- client->nickname);
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Welcome to the SILC Network %s@%s",
+ username, sock->hostname));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Your host is %s, running version %s",
+ server->config->server_info->server_name,
+ server_version));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Your connection is secured with %s cipher, "
+ "key length %d bits",
+ client->send_key->cipher->name,
+ client->send_key->cipher->key_len));
+ SILC_SERVER_SEND_NOTIFY(server, sock, SILC_NOTIFY_TYPE_NONE,
+ ("Your current nickname is %s",
+ client->nickname));
/* Send motd */
silc_server_send_motd(server, sock);
SilcIDCacheEntry cache;
SilcServerID *server_id;
unsigned char *server_name, *id_string;
+ unsigned short id_len;
SILC_LOG_DEBUG(("Creating new server"));
/* Parse the incoming packet */
silc_buffer_unformat(buffer,
- SILC_STR_UI16_STRING_ALLOC(&id_string),
+ SILC_STR_UI16_NSTRING_ALLOC(&id_string, &id_len),
SILC_STR_UI16_STRING_ALLOC(&server_name),
SILC_STR_END);
+ if (id_len > buffer->len) {
+ silc_free(id_string);
+ silc_free(server_name);
+ return NULL;
+ }
+
/* Get Server ID */
- server_id = silc_id_str2id(id_string, SILC_ID_SERVER);
+ server_id = silc_id_payload_parse_id(id_string, id_len);
silc_free(id_string);
/* Update client entry */
SilcIDList id_list;
SilcServerEntry tmpserver, router;
SilcSocketConnection router_sock;
+ SilcIDPayload idp;
SilcIdType id_type;
- unsigned char *id_string;
void *id, *tmpid;
SILC_LOG_DEBUG(("Processing new ID"));
packet->src_id_type != SILC_ID_SERVER)
return;
- silc_buffer_unformat(buffer,
- SILC_STR_UI_SHORT(&id_type),
- SILC_STR_UI16_STRING_ALLOC(&id_string),
- SILC_STR_END);
+ idp = silc_id_payload_parse(buffer);
+ if (!idp)
+ return;
+
+ id_type = silc_id_payload_get_type(idp);
/* Normal server cannot have other normal server connections */
if (id_type == SILC_ID_SERVER && sock->type == SILC_SOCKET_TYPE_SERVER)
goto out;
- id = silc_id_str2id(id_string, id_type);
+ id = silc_id_payload_get_id(idp);
if (!id)
goto out;
break;
default:
- goto out;
break;
}
out:
- silc_free(id_string);
+ silc_id_payload_free(idp);
}
/* Received packet to remove a user from a channel. Routers notify other
#define SILC_SERVER 0
#define SILC_ROUTER 1
+/* Macros */
+
+/* This macro is used to send notify messages with formatted string. The
+ string is formatted with arguments and the formatted string is sent as
+ argument. */
+#define SILC_SERVER_SEND_NOTIFY(server, sock, type, fmt) \
+do { \
+ char *__fmt__ = silc_format fmt; \
+ silc_server_send_notify(server, sock, type, 1, __fmt__, strlen(__fmt__)); \
+ silc_free(__fmt__); \
+} while(0);
+
/* Prototypes */
int silc_server_alloc(SilcServer *new_server);
void silc_server_free(SilcServer server);
void silc_server_send_notify(SilcServer server,
SilcSocketConnection sock,
SilcNotifyType type,
- unsigned int argc,
- unsigned int format,
- const char *fmt, ...);
+ unsigned int argc, ...);
void silc_server_send_notify_dest(SilcServer server,
SilcSocketConnection sock,
void *dest_id,
SilcIdType dest_id_type,
SilcNotifyType type,
- unsigned int argc,
- unsigned int format,
- const char *fmt, ...);
+ unsigned int argc, ...);
void silc_server_send_notify_to_channel(SilcServer server,
SilcChannelEntry channel,
SilcNotifyType type,
- unsigned int argc,
- unsigned int format,
- const char *fmt, ...);
+ unsigned int argc, ...);
+void silc_server_send_notify_on_channels(SilcServer server,
+ SilcClientEntry client,
+ SilcNotifyType type,
+ unsigned int argc, ...);
void silc_server_send_new_id(SilcServer server,
SilcSocketConnection sock,
int broadcast,
;;
esac
-AM_INIT_AUTOMAKE(silc, 20001009)
+AM_INIT_AUTOMAKE(silc, 20001101)
AC_PREREQ(2.3)
AM_CONFIG_HEADER(includes/silcdefs.h)
esac ], CFLAGS="-O2 -g $CFLAGS"
AC_MSG_RESULT(no))
-
# SOCKS4 support checking
AC_MSG_CHECKING(whether to support SOCKS4)
AC_ARG_WITH(socks4,
# Other configure scripts
#AC_CONFIG_SUBDIRS(lib/zlib)
AC_CONFIG_SUBDIRS(lib/silcmath/gmp)
+AC_CONFIG_SUBDIRS(lib/trq)
AC_OUTPUT( \
Makefile
indicate the status of the protocol. Implementations may map the
status types to human readable error message. All types except the
SILC_SKE_STATUS_OK type must be sent in SILC_PACKET_FAILURE packet.
-Following status types are defined:
+The length of status is 32 bits (4 bytes). Following status types are
+defined:
.in 6
0 SILC_SKE_STATUS_OK
8 SILC_SKE_STATUS_INCORRECT_SIGNATURE
Provided signature was incorrect.
+
+
+9 SILC_SKE_STATUS_BAD_VERSION
+
+ Provided version string was not acceptable.
.in 3
to indicate the status of the protocol. Implementations may map the
status types to human readable error message. All types except the
SILC_AUTH_STATUS_OK type must be sent in SILC_PACKET_FAILURE packet.
-Following status types are defined:
+The length of status is 32 bits (4 bytes). Following status types are
+defined:
0 SILC_AUTH_OK
server to client, although it may be sent from server to another
server as well. Client never sends this packet. Server may
send this packet to channel as well when the packet is
- distributed to all clients on the channel. Receiver of this
- packet may ignore the packet if it chooses so. However, it
- should not be ignored.
+ distributed to all clients on the channel.
Payload of the packet: See section 2.3.7 Notify Payload.
packet maybe sent to entity that is indirectly connected to
the sender.
+ When received, the server or router must distribute
+ SILC_NOTIFY_TYPE_JOIN to local clients on the channel.
+
Payload of the packet: See section 2.3.21 New Channel User
Payload
packet SILC_PACKET_NEW_CHANNEL_USER except that it may
include several payloads. Client must not send this packet.
+ When received, the server or router must distribute
+ SILC_NOTIFY_TYPE_JOIN to local clients on the channel.
+
Payload of the packet: See section 2.3.23 New Channel User
List Payload
packet. This packet maybe sent to entity that is indirectly
connected to the sender.
+ When received and the replaced ID is Client ID the server or
+ router must distribute SILC_NOTIFY_TYPE_NICK_CHANGE to the
+ local clients on the channels (if any) of the client whose
+ ID was changed. However, the notify type must be sent only
+ once per client.
+
Payload of the packet: See section 2.3.24 Replace ID Payload
this packet. This packet maybe sent to entity that is
indirectly connected to the sender.
+ When received and the replaced ID is Client ID the server or
+ router must distribute SILC_NOTIFY_TYPE_SIGNOFF to the
+ local clients on the channels (if any) of the client whose
+ ID was changed. However, the notify type must be sent only
+ once per client.
+
Payload of the packet: See section 2.3.25 Remove ID Payload
client has left a channel. This packet maybe sent to entity
that is indirectly connected to the sender.
+ When received, the server or router must distribute
+ SILC_NOTIFY_TYPE_LEAVEW to local clients on the channel.
+
Payload of the packet: See section 2.3.26 Remove Channel User
Payload
Notify payload is used to send notify messages. The payload is usually
sent from server to client, however, server may send it to another
-server as well. Client must not send this payload. The receiver of
-this payload may totally ignore the contents of the payload, however,
-notify message should be noted and possibly logged.
+server as well. This payload may also be sent to a channel. Client must
+not send this payload. The receiver of this payload may totally ignore the
+contents of the payload, however, notify message should be noted and
+possibly logged.
The payload may only be sent with SILC_PACKET_NOTIFY packet. It must
not be sent in any other packet type. Following diagram represents the
1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Notify Type | Message Length |
-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-| Argument Nums | |
-+-+-+-+-+-+-+-+-+ +
-| |
-~ Notify Message ~
-| |
+| Notify Type | Payload Length |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+| Argument Nums |
++-+-+-+-+-+-+-+-+
.in 3
.ce
o Notify Type (2 bytes) - Indicates the type of the notify
message.
-o Message Length (2 bytes) - Length of the Notify Message area
- not ncluding the length of any other fields in the payload.
+o Payload Length (2 bytes) - Length of the entire Notify Payload
+ including any associated Argument Payloads.
o Argument Nums (2 bytes) - Indicates the number of Argument
Payloads associated to this payload. Notify types may define
arguments to be send along the notify message.
-
-o Notify Message (variable length) - Human readable notify
- message. The format of this message is implementation specific.
- The message can be for example "%s has joined channel %s".
.in 3
-Following notify types has been defined:
+Following list of currently defined notify types. The format for notify
+arguments is same as in SILC commands described in [SILC1]. Also, all
+ID's sent in arguments are sent inside ID Payload.
.in 6
0 SILC_NOTIFY_TYPE_NONE
- If no specific notify type apply for the notify
- message this type may be used.
+ If no specific notify type apply for the notify message this type
+ may be used.
+
+ Max Arguments: 1
+ Arguments: (1) <message>
+
+ The <message> is implementation specific free text string. Receiver
+ may ignore this message.
- No arguments associated to this type.
1 SILC_NOTIFY_TYPE_INVITE
- Sent when receiver has been invited to a channel.
+ Sent when receiver has been invited to a channel. This type must be
+ sent directly to the invited client.
+
+ Max Arguments: 2
+ Arguments: (1) <Client ID> (2) <Channel ID>
+
+ The <Client ID> is the client who invites the receiver of this type
+ to channel indicated by <Channel ID>.
- This type includes two arguments: nickname and channel name.
2 SILC_NOTIFY_TYPE_JOIN
- Sent when client has joined to a channel.
+ Sent when client has joined to a channel. The server must distribute
+ this type only to the local clients on the channel and then send
+ SILC_PACKET_NEW_CHANNEL_USER packet to its primary route. The router
+ or server receiving the packet distributes this type to the local
+ clients on the channel. See description of SILC_PACKET_NEW_CHANNEL_USER
+ packet for more information.
+
+ Max Arguments: 1
+ Arguments: (1) <Client ID>
+
+ The <Client ID> is the client that joined to the channel.
- This type includes six arguments: Client ID, nickname, username,
- hostname, Channel ID and channel name. The Client ID and Channel ID
- are sent inside ID Payload.
3 SILC_NOTIFY_TYPE_LEAVE
- Sent when client has left a channel.
+ Sent when client has left a channel. The server must distribute
+ this type only to the local clients on the channel and then send
+ SILC_PACKET_REMOVE_CHANNEL_USER packet to its primary route. The
+ router or server receiving the packet distributes this type to the
+ local clients on the channel. See description of
+ SILC_PACKET_REMOVE_CHANNEL_USER packet for more information.
+
+ Max Arguments: 1
+ Arguments: (1) <Client ID>
+
+ The <Client ID> is the client who left the channel.
- This type includes four arguments: nickname, server name,
- Channel ID and channel name. The Channel ID is sent inside ID
- Payload.
4 SILC_NOTIFY_TYPE_SIGNOFF
- Sent when client signoffs from SILC network.
+ Sent when client signoffs from SILC network. This type is sent only
+ if the client was joined to any channel. This type is sent by server
+ or router when SILC_PACKET_REMOVE_ID packet has been received. See
+ detailed information from description of SILC_PACKET_REMOVE_ID packet.
+
+ Max Arguments: 1
+ Arguments: (1) <Client ID>
+
+ The <Client ID> is the client who left SILC network.
- This type includes three arguments: nickname, server name and
- Channel ID. The Channel ID is sent inside ID Payload.
5 SILC_NOTIFY_TYPE_TOPIC_SET
- Sent when topic is set/changed on a channel.
+ Sent when topic is set/changed on a channel. This type must be sent
+ only to the clients who is joined on the channel whose topic was
+ set or changed.
+
+ Max Arguments: 2
+ Arguments: (1) <Client ID> (2) <topic>
+
+ The <Client ID> is the client who set or changed the <topic>.
- This type includes four arguments: Channel ID, topic, nickname and
- hostname. The Channel ID is sent inside ID Payload.
6 SILC_NOTIFY_TYPE_NICK_CHANGE
- Sent when client changes nick on a channel.
+ Sent when client changes nick on a channel. This type is sent only if
+ the client has joined to any channel. This type is sent by server or
+ router when SILC_PACKET_REPLACE_ID packet has been received. See
+ detailed information from description of SILC_PACKET_REPLACE_ID packet.
+
+ Max Arguments: 2
+ Arguments: (1) <Old Client ID> (2) <New Client ID>
+
+ The <Old Client ID> is the old ID of the client who changed the
+ nickname. The <New Client ID> is the new ID generated by the change
+ of the nickname.
+
+
+7 SILC_NOTIFY_TYPE_CMODE_CHANGE
+
+ Sent when channel mode has changed. This type must be sent only to
+ the clients who is joined on the channel whose mode was changed.
+
+ Max Arguments: 2
+ Arguments: (1) <Client ID> (2) <mode mask>
+
+ The <Client ID> is the client who changed the mode. The <mode mask>
+ is the new mode mask of the channel.
+
+
+8 SILC_NOTIFY_TYPE_CUMODE_CHANGE
+
+ Sent when user mode on channel has changed. This type must be sent
+ only to the clients who is joined on the channel where the target
+ client is on.
+
+ Max Arguments: 3
+ Arguments: (1) <Client ID> (2) <mode mask>
+ (3) <Target Client ID>
+
+ The <Client ID> is the client who changed the mode. The <mode mask>
+ is the new mode mask of the channel. The <Target Client ID> is the
+ client whose mode was changed.
+
+
+9 SILC_NOTIFY_TYPE_MOTD
+
+ Sent when Message of the Day (motd) is sent to client.
+
+ Max Arguments: 1
+ Arguments: (1) <motd>
- This type includes two arguments: nickname and Channel ID.
- The Channel ID is sent inside ID Payload.
+ The <motd> is the Message of the Day.
.in 3
Notify types starting from 16384 are reserved for private notify
Note that the command reply is usually sent only after client has sent
the command request but server is allowed to send command reply packet
to client even if client has not requested the command. Client may,
-however, choose not to accept the command reply, but there are some
-command replies that the client should accept. Example of a such
-command reply is reply to SILC_COMMAND_CMODE command that the server
-uses to distribute the channel mode on all clients on the channel
-when the mode has changed.
+however, choose ignore the command reply, but should not.
It is expected that some of the commands may be miss-used by clients
resulting various problems on the server side. Every implementation
1 SILC_COMMAND_WHOIS
Max Arguments: 3
- Arguments: (1) <nickname>[@<server>] (2) [<Client ID>]
+ Arguments: (1) [<nickname>[@<server>]] (2) [<Client ID>]
(3) [<count>]
Whois command is used to query various information about specific
3 SILC_COMMAND_IDENTIFY
Max Arguments: 2
- Arguments: (1) <nickname>[@<server>] (2) [<Client ID>]
+ Arguments: (1) [<nickname>[@<server>]] (2) [<Client ID>]
(3) [<count>]
Identify. Identify command is almost analogous to WHOIS command,
be based on specific nickname request.
Implementations may not want to give interface access to this
- command as it is hardly a command that would be used a end user.
+ command as it is hardly a command that would be used by an end user.
However, it must be implemented as it is used with private message
sending.
nicknames in SILC are case-sensitive which must be taken into
account when searching clients by nickname.
+ When nickname is changed new Client ID is generated. Server must
+ distribute SILC_NOTIFY_TYPE_NICK_CHANGE to local clients on the
+ channels (if any) the client is joined on. Then it must send
+ SILC_PACKET_REPLACE_ID to its primary route to replace the old
+ Client ID with the new one.
+
Reply messages to the command:
Max Arguments: 2
SILC_STATUS_ERR_TOO_MANY_PARAMS
-
-
-
-
5 SILC_COMMAND_LIST
Max Arguments: 2
SILC_STATUS_ERR_AUTH_FAILED
-
-
-
14 SILC_COMMAND_JOIN
Max Arguments: 3
Reply messages to the command:
- Max Arguments: 5
+ Max Arguments: 6
Arguments: (1) <Status Payload> (2) <channel>
(3) <Channel ID> (4) <channel mode mask>
(5) [<ban mask>] (6) [<invite list>]
17 SILC_COMMAND_CMODE
- Max Arguments: 8
+ Max Arguments: 7
Arguments: (1) <Channel ID> (2) <channel mode mask>
(3) [<user limit>] (4) [<passphrase>]
(5) [<ban mask>] (6) [<invite list>]
- (7) [<Client ID>] (8) [<cipher>[:<key len>]]
+ (7) [<cipher>[:<key len>]]
This command is used by client to set or change channel flags on
a channel. Channel has several modes that set various properties
the same channel and poses sufficient privileges to be able to
change the mode.
+ When the mode is changed SILC_NOTIFY_TYPE_CMODE_CHANGE notify
+ type is distributed to the channel.
+
Following channel modes are defined:
0x0000 SILC_CMODE_NONE
unsetting a ban mask the mask must be provided as
argument. Channel founder and channel operator may
set/unset this mode. Channel founder may not be
- added to the ban list.
+ added to the ban list. <ban mask> is comma (`,') separated
+ list of banned clients in following format:
+
+ [<nickname>!][<username>]@[<hostname>]
+
+ Wildcards maybe used when banning clients.
Typical implementation would use [+|-]b on user interface
to set/unset this mode.
- 0x0100 SILC_CMODE_INVITE
+ 0x0100 SILC_CMODE_INVITE_LIST
Invite list has been set to the channel. The invite list
can be used to mark the clients that is able to join
be invite-only channel. The <invite list> argument is the
set invite mask. When unsetting entry from the invite list
the entry must be provided as argument. Channel founder and
- channel operator may set/unset this mode.
+ channel operator may set/unset this mode. The <invite list>
+ is command (`,') separated list of invited clients in following
+ format:
- Typical implementation would use [+|-]I on user interface
- to set/unset this mode.
+ [<nickname>!][<username>]@[<hostname>]
-
- 0x0200 SILC_CMODE_OPERATOR
+ Wildcards maybe used when setting the invite list.
- Sets channel operator privileges on the channel for a
- client on the channel. The <Client ID> argument is the
- target client on the channel. Channel founder and
- channel operator may set/unset (promote/demote) this
- mode.
-
- Typical implementation would use [+|-]o on user interface
+ Typical implementation would use [+|-]I on user interface
to set/unset this mode.
-
- 0x0400 SILC_CMODE_CIPHER
+
+ 0x0200 SILC_CMODE_CIPHER
Sets specific cipher to be used to protect channel
traffic. The <cipher> argument is the requested cipher.
When set or unset the server must re-generate new
channel key. If <key len> argument is specified with
<cipher> argument the new key is generated of <key len>
- length.
+ length in bits. Only channel founder may set the cipher of
+ the channel. When unset the new key is generated using
+ default cipher for the channel.
Typical implementation would use [+|-]c on user interface
to set/unset this mode.
Arguments: (1) <Status Payload> (2) <channel mode mask>
This command replies with the changed channel mode mask that
- client is required to keep locally. The same mask is also
- sent to all clients on channel by sending additional command
- reply to them.
+ client is required to keep locally.
Status messages:
SILC_STATUS_ERR_NO_CHANNEL_ID
SILC_STATUS_ERR_NO_CHANNEL_PRIV
SILC_STATUS_ERR_UNKNOWN_MODE
- SILC_STATUS_ERR_NO_CLIENT_ID
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+
+ 19 SILC_COMMAND_CUMODE
+
+ Max Arguments: 3
+ Arguments: (1) <Channel ID> (2) <mode mask>
+ (3) <Client ID>
+
+ This command is used by client to change channel user modes on
+ channel. Users on channel may have some special modes and this
+ command is used by channel operators to set or change these modes.
+ The <Channel ID> is the ID of the target channel. The <mode mask>
+ is OR'ed mask of modes. The <Client ID> is the target client.
+ The client changing channel user modes must be on the same channel
+ as the target client and poses sufficient privileges to be able to
+ change the mode.
+
+ When the mode is changed SILC_NOTIFY_TYPE_CUMODE_CHANGE notify
+ type is distributed to the channel.
+
+ Following channel modes are defined:
+ 0x0000 SILC_CUMODE_NONE
+ No specific mode. This is the normal situation for client.
+ Also, this is the mode set when removing all modes from client.
- 18 SILC_COMMAND_KICK
+ 0x0001 SILC_CUMODE_FOUNDER
+
+ The client is channel founder of the channel. This mode
+ cannot be set by other client, it is set by the server when
+ the channel was founded (created). The mode is provided
+ because client may remove the founder rights from itself.
+
+
+ 0x0002 SILC_CUMODE_OPERATOR
+
+ Sets channel operator privileges on the channel for a
+ client on the channel. Channel founder and channel operator
+ may set/unset (promote/demote) this mode.
+
+
+ Reply messages to the command:
+
+ Max Arguments: 3
+ Arguments: (1) <Status Payload> (2) <channel user mode mask>
+ (3) <Client ID>
+
+ This command replies with the changed channel user mode mask that
+ client is required to keep locally. The <Client ID> is the target
+ client.
+
+ Status messages:
+
+ SILC_STATUS_OK
+ SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ SILC_STATUS_ERR_TOO_MANY_PARAMS
+ SILC_STATUS_ERR_NOT_REGISTERED
+ SILC_STATUS_ERR_NOT_ON_CHANNEL
+ SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID
+ SILC_STATUS_ERR_BAD_CHANNEL_ID
+ SILC_STATUS_ERR_NO_CHANNEL_ID
+ SILC_STATUS_ERR_NO_CHANNEL_PRIV
+ SILC_STATUS_ERR_UNKNOWN_MODE
+ SILC_STATUS_ERR_NO_SUCH_CLIENT_ID
+
+
+ 19 SILC_COMMAND_KICK
Max Arguments: 3
Arguments: (1) <channel> (2) <Client ID>
SILC_STATUS_ERR_NO_CLIENT_ID
- 19 SILC_COMMAND_RESTART
+ 20 SILC_COMMAND_RESTART
Max Arguments: 0
Arguments: None
- 20 SILC_COMMAND_CLOSE
+ 21 SILC_COMMAND_CLOSE
Max Arguments: 1
Arguments: (1) <Server ID>
SILC_STATUS_ERR_NO_SUCH_SERVER_ID
- 21 SILC_COMMAND_DIE
+ 22 SILC_COMMAND_DIE
Max Arguments: 0
Arguments: None
SILC_STATUS_ERR_NO_SERVER_PRIV
- 22 SILC_COMMAND_SILCOPER
+ 23 SILC_COMMAND_SILCOPER
Max Arguments: 2
Arguments: (1) <username> (2) <authentication data>
SILC_STATUS_ERR_AUTH_FAILED
- 23 SILC_COMMAND_LEAVE
+ 24 SILC_COMMAND_LEAVE
Max Arguments: 1
Arguments: (1) <Channel ID>
SILC_STATUS_ERR_NO_CHANNEL_ID
- 24 SILC_COMMAND_NAMES
+ 25 SILC_COMMAND_NAMES
Max Arguments: 1
Arguments: (1) <Channel ID>
command must not send the list of users, as private and secret
channels cannot be seen by outside. In this case the returned
name list may include a indication that the server could not
- resolve the names of the users on the channel.
+ resolve the names of the users on the channel. Also, in this case
+ Client ID's or client modes are not sent either.
Reply messages to the command:
- Max Arguments: 3
+ Max Arguments: 5
Arguments: (1) <Status Payload> (2) <Channel ID>
(3) <name list> (4) <Client ID list>
+ (5) <client mode list>
This command replies with the Channel ID of the requested channel,
comma separated list of users on the channel and Client ID list
of the users on the list. The Client ID list has Client ID's
of all users in the list. First Client ID in the list must be
- the Client ID of the first user in <name list>. The Client ID
- List is formed by adding Client ID's each after each. Note that
- the Client ID list is binary data.
+ the Client ID of the first user in <name list>. The <Client ID
+ list> is formed by adding Client ID's each after each. Note that
+ the Client ID list is binary data and the length of each ID must
+ be snooped from the data. The <client mode list> is formed by
+ adding client's user modes on the channel each after each (4 bytes
+ each).
Status messages:
SILC_STATUS_ERR_NOT_ON_CHANNEL
- 25 - 199
+ 26 - 199
Currently undefined commands.
25 SILC_STATUS_ERR_NOT_ON_CHANNEL
"You are not on that channel". The command were specified for
- client user is not currently on.
+ channel user is not currently on.
+
+ 26 SILC_STATUS_ERR_USER_NOT_ON_CHANNEL
+
+ "They are not on channel". The requested target client is not
+ on requested channel.
- 26 SILC_STATUS_ERR_USER_ON_CHANNEL
+ 27 SILC_STATUS_ERR_USER_ON_CHANNEL
"User already on channel". User were invited on channel they
already are on.
- 27 SILC_STATUS_ERR_NOT_REGISTERED
+ 28 SILC_STATUS_ERR_NOT_REGISTERED
"You have not registered". User executed command that requires
the client to be registered on the server before it may be
executed.
- 28 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
+ 29 SILC_STATUS_ERR_NOT_ENOUGH_PARAMS
"Not enough parameters". Command requires more parameters
than provided.
- 29 SILC_STATUS_ERR_TOO_MANY_PARAMS
+ 30 SILC_STATUS_ERR_TOO_MANY_PARAMS
"Too many parameters". Too many parameters were provided
for the command.
- 30 SILC_STATUS_ERR_PERM_DENIED
+ 31 SILC_STATUS_ERR_PERM_DENIED
"Your host is not among the privileged". The client tried to
register on server that does not allow this host to connect.
- 31 SILC_STATUS_ERR_BANNED_FROM_SERVER
+ 32 SILC_STATUS_ERR_BANNED_FROM_SERVER
"You are banned from this server". The client tried to register
on server that has explicitly denied this host to connect.
- 32 SILC_STATUS_ERR_BAD_PASSWORD
+ 33 SILC_STATUS_ERR_BAD_PASSWORD
"Cannot join channel. Incorrect password". Password provided for
channel were not accepted.
- 33 SILC_STATUS_ERR_CHANNEL_IS_FULL
+ 34 SILC_STATUS_ERR_CHANNEL_IS_FULL
"Cannot join channel. Channel is full". The channel is full
and client cannot be joined to it.
- 34 SILC_STATUS_ERR_NOT_INVITED
+ 35 SILC_STATUS_ERR_NOT_INVITED
"Cannot join channel. You have not been invited". The channel
is invite only channel and client has not been invited.
- 35 SILC_STATUS_ERR_BANNED_FROM_CHANNEL
+ 36 SILC_STATUS_ERR_BANNED_FROM_CHANNEL
"Cannot join channel. You have been banned". The client has
been banned from the channel.
- 36 SILC_STATUS_ERR_UNKNOWN_MODE
+ 37 SILC_STATUS_ERR_UNKNOWN_MODE
"Unknown mode". Mode provided by the client were unknown to
the server.
- 37 SILC_STATUS_ERR_NOT_YOU
+ 38 SILC_STATUS_ERR_NOT_YOU
"Cannot change mode for other users". User tried to change
someone else's mode.
- 38 SILC_STATUS_ERR_NO_CHANNEL_PRIV
+ 39 SILC_STATUS_ERR_NO_CHANNEL_PRIV
"Permission denied. You are not channel operator". Command may
be executed only by channel operator.
- 39 SILC_STATUS_ERR_NO_SERVER_PRIV
+ 40 SILC_STATUS_ERR_NO_SERVER_PRIV
"Permission denied. You are not server operator". Command may
be executed only by server operator.
- 40 SILC_STATUS_ERR_NO_ROUTER_PRIV
+ 41 SILC_STATUS_ERR_NO_ROUTER_PRIV
"Permission denied. You are not SILC operator". Command may be
executed only by router (SILC) operator.
- 41 SILC_STATUS_ERR_BAD_NICKNAME
+ 42 SILC_STATUS_ERR_BAD_NICKNAME
"Bad nickname". Nickname requested contained illegal characters
or were malformed.
- 42 SILC_STATUS_ERR_BAD_CHANNEL
+ 43 SILC_STATUS_ERR_BAD_CHANNEL
"Bad channel name". Channel requested contained illegal characters
or were malformed.
- 43 SILC_STATUS_ERR_AUTH_FAILED
+ 44 SILC_STATUS_ERR_AUTH_FAILED
"Authentication failed". The authentication data sent as
argument were wrong and thus authentication failed.
#include "silcpacket.h"
#include "silcnotify.h"
+/* TRQ (SilcList API and SilcDList API) */
+#include "silclist.h"
+#include "silcdlist.h"
+
#ifdef SILC_SIM
/* SILC Module library includes */
#include "silcsim.h"
silcmath \
silcske \
silcutil \
- silcclient
+ silcclient \
+ trq
# zlib
# SILC Library dirs
silcsim \
silcmath \
silcske \
- silcutil
+ silcutil \
+ trq
# SILC Client Library dirs
SILCCLIENTLIB_DIRS = \
INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
-I../silcsim -I../.. -I../../includes -I../silccore -I../silcutil \
- -I../silcmath/gmp
+ -I../silcmath/gmp -I../trq
INCLUDES = -I. -I.. -I../silccore -I../silccrypt -I../silcutil \
-I../silcmath -I../silcske -I../silcsim \
-I../../includes \
- -I../silcmath/gmp
+ -I../silcmath/gmp -I../trq
pointers must be set before calling the initializing function:
client->username
+ client->hostname
client->realname
client->pkcs
client->public_key
out:
silc_buffer_clear(buffer);
+ if (packet->src_id)
+ silc_free(packet->src_id);
+ if (packet->dst_id)
+ silc_free(packet->dst_id);
silc_free(packet);
silc_free(parse_ctx);
}
* protocol and it will call the final callback.
*/
if (sock->protocol) {
- sock->protocol->state = SILC_PROTOCOL_STATE_ERROR;
+ sock->protocol->state = SILC_PROTOCOL_STATE_FAILURE;
sock->protocol->execute(client->timeout_queue, 0,
sock->protocol, sock->sock, 0, 0);
+
+ /* XXX We have only two protocols currently thus we know what this
+ failure indication is. */
+ if (buffer->len >= 4) {
+ unsigned int failure;
+
+ SILC_GET32_MSB(failure, buffer->data);
+
+ /* Notify application */
+ client->ops->failure(client, sock->user_data, sock->protocol,
+ (void *)failure);
+ }
}
break;
case SILC_PACKET_REJECT:
/*
* Received notify message
*/
- silc_client_notify_by_server(client, sock, buffer);
+ silc_client_notify_by_server(client, sock, packet);
break;
case SILC_PACKET_ERROR:
* user changes nickname but in that case the new ID is received
* as command reply and not as this packet type.
*/
- unsigned char *id_string;
- unsigned short id_type;
-
- silc_buffer_unformat(buffer,
- SILC_STR_UI_SHORT(&id_type),
- SILC_STR_UI16_STRING_ALLOC(&id_string),
- SILC_STR_END);
-
- if ((SilcIdType)id_type != SILC_ID_CLIENT)
+ SilcIDPayload idp;
+
+ idp = silc_id_payload_parse(buffer);
+ if (silc_id_payload_get_type(idp) != SILC_ID_CLIENT)
break;
- silc_client_receive_new_id(client, sock, id_string);
- silc_free(id_string);
+ silc_client_receive_new_id(client, sock, idp);
+ silc_id_payload_free(idp);
break;
}
silc_free(msg);
}
+/* Called when notify is received and some async operation (such as command)
+ is required before processing the notify message. This calls again the
+ silc_client_notify_by_server and reprocesses the original notify packet. */
+
+static void silc_client_notify_by_server_pending(void *context)
+{
+ SilcPacketContext *p = (SilcPacketContext *)context;
+ silc_client_notify_by_server(p->context, p->sock, p);
+ if (p->src_id)
+ silc_free(p->src_id);
+ if (p->dst_id)
+ silc_free(p->dst_id);
+ silc_buffer_free(p->buffer);
+ silc_free(p);
+}
+
/* Received notify message from server */
void silc_client_notify_by_server(SilcClient client,
SilcSocketConnection sock,
- SilcBuffer message)
+ SilcPacketContext *packet)
{
+ SilcBuffer buffer = packet->buffer;
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
SilcNotifyPayload payload;
SilcNotifyType type;
SilcClientID *client_id = NULL;
SilcChannelID *channel_id = NULL;
- SilcIDPayload idp;
SilcClientEntry client_entry;
+ SilcClientEntry client_entry2;
SilcChannelEntry channel;
SilcIDCacheEntry id_cache = NULL;
unsigned char *tmp;
- unsigned int tmp_len;
+ unsigned int tmp_len, mode;
- payload = silc_notify_payload_parse(message);
+ payload = silc_notify_payload_parse(buffer);
type = silc_notify_get_type(payload);
args = silc_notify_get_args(payload);
+ if (!args)
+ goto out;
switch(type) {
case SILC_NOTIFY_TYPE_NONE:
+ /* Notify application */
+ client->ops->notify(client, conn, type,
+ silc_argument_get_arg_type(args, 1, NULL));
break;
+
case SILC_NOTIFY_TYPE_INVITE:
/*
- * Someone invited me to a channel. Nothing interesting to do here.
+ * Someone invited me to a channel. Find Client and Channel entries
+ * for the application.
*/
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry and if not found query it */
+ client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ if (!client_entry) {
+ SilcPacketContext *p = silc_packet_context_dup(packet);
+ p->context = (void *)client;
+ p->sock = sock;
+ silc_client_command_pending(SILC_COMMAND_WHOIS,
+ silc_client_notify_by_server_pending, p);
+ goto out;
+ }
+
+ /* Get Channel ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ channel_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* XXX Will ALWAYS fail because currently we don't have way to resolve
+ channel information for channel that we're not joined to. */
+ /* XXX ways to fix: use (extended) LIST command, or define the channel
+ name to the notfy type when name resolving is not mandatory. */
+ /* Find channel entry */
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache))
+ goto out;
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Notify application */
+ client->ops->notify(client, conn, type, client_entry, channel);
break;
+
case SILC_NOTIFY_TYPE_JOIN:
/*
* Someone has joined to a channel. Get their ID and nickname and
* cache them for later use.
*/
- /* Get client ID (it's in ID payload) */
+ /* Get Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- client_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
+ if (!tmp)
+ goto out;
- /* If it's my ID, ignore */
- if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
- break;
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
- /* Check if we have that ID already */
- if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
- SILC_ID_CLIENT, &id_cache)) {
- /* Add client to cache */
- client_entry = silc_calloc(1, sizeof(*client_entry));
- client_entry->id = client_id;
- client_entry->nickname =
- strdup(silc_argument_get_arg_type(args, 2, NULL));
- silc_idcache_add(conn->client_cache, client_entry->nickname,
- SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
- client_id = NULL;
- } else {
- client_entry = (SilcClientEntry)id_cache->context;
+ /* Find Client entry and if not found query it */
+ client_entry = silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ if (!client_entry) {
+ SilcPacketContext *p = silc_packet_context_dup(packet);
+ p->context = (void *)client;
+ p->sock = sock;
+ silc_client_command_pending(SILC_COMMAND_WHOIS,
+ silc_client_notify_by_server_pending, p);
+ goto out;
}
- /* Get Channel ID (it's in ID payload) */
- tmp = silc_argument_get_arg_type(args, 5, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- channel_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
-
- /* Find channel entry */
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
/* Add client to channel */
for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i] == NULL) {
- channel->clients[channel->clients_count] = client_entry;
+ if (channel->clients[i].client == NULL) {
+ channel->clients[channel->clients_count].client = client_entry;
channel->clients_count++;
break;
}
channel->clients = silc_realloc(channel->clients,
sizeof(*channel->clients) *
(channel->clients_count + 1));
- channel->clients[channel->clients_count] = client_entry;
+ channel->clients[channel->clients_count].client = client_entry;
+ channel->clients[channel->clients_count].mode = 0;
channel->clients_count++;
}
/* XXX add support for multiple same nicks on same channel. Check
for them here */
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, channel);
break;
+
case SILC_NOTIFY_TYPE_LEAVE:
/*
* Someone has left a channel. We will remove it from the channel but
* we'll keep it in the cache in case we'll need it later.
*/
- /* Get nickname */
- /* XXX Protocol must be changed to send Client ID */
+ /* Get Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-
- /* Find channel entry */
- /* XXX this can return wrong entry */
- client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
if (!client_entry)
- break;
-
- /* Get Channel ID (it's in ID payload) */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- channel_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
-
- /* Find channel entry */
+ goto out;
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
-
+
channel = (SilcChannelEntry)id_cache->context;
-
+
/* Remove client from channel */
for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i] == client_entry) {
- channel->clients[i] = NULL;
+ if (channel->clients[i].client == client_entry) {
+ channel->clients[i].client = NULL;
channel->clients_count--;
break;
}
}
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, channel);
break;
+
case SILC_NOTIFY_TYPE_SIGNOFF:
/*
- * Someone left SILC. We'll remove it from the channel and from cache.
+ * Someone left SILC. We'll remove it from all channels and from cache.
*/
- /* Get nickname */
- /* XXX Protocol must be changed to send Client ID */
+ /* Get Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-
- /* Find channel entry */
- /* XXX this can return wrong entry */
- client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
if (!client_entry)
- break;
-
- /* Get Channel ID (it's in ID payload) */
- tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- channel_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
-
- /* Find channel entry */
- if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
- SILC_ID_CHANNEL, &id_cache))
- break;
-
- channel = (SilcChannelEntry)id_cache->context;
-
- /* Remove client from channel */
- for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i] == client_entry) {
- channel->clients[i] = NULL;
- channel->clients_count--;
- break;
- }
- }
+ goto out;
+
+ /* Remove from all channels */
+ silc_client_remove_from_channels(client, conn, client_entry);
/* Remove from cache */
silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
client_entry->id);
+
+ /* Notify application */
+ client->ops->notify(client, conn, type, client_entry);
+
+ /* Free data */
+ if (client_entry->nickname)
+ silc_free(client_entry->nickname);
+ if (client_entry->server)
+ silc_free(client_entry->server);
+ if (client_entry->id)
+ silc_free(client_entry->id);
+ if (client_entry->send_key)
+ silc_cipher_free(client_entry->send_key);
+ if (client_entry->receive_key)
+ silc_cipher_free(client_entry->receive_key);
break;
+
case SILC_NOTIFY_TYPE_TOPIC_SET:
/*
- * Someone set the topic on a channel. Nothing interesting to do here.
+ * Someone set the topic on a channel.
*/
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ if (!client_entry)
+ goto out;
+
+ /* Get topic */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache))
+ break;
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, tmp, channel);
break;
+
case SILC_NOTIFY_TYPE_NICK_CHANGE:
/*
- * Someone changed their nickname. Cache the new Client ID.
+ * Someone changed their nickname. If we don't have entry for the new
+ * ID we will query it and return here after it's done. After we've
+ * returned we fetch the old entry and free it and notify the
+ * application.
*/
- /* XXX Protocol must be changed to send the old Client ID and the
- new Client ID. Now we get only nickname, thus, we'll make NAMES
- to receive the new ID. Other choice is to do IDENTIFY but I'm
- doing NAMES for now. */
+ /* Get new Client ID */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
- /* Get nickname */
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Ignore my ID */
+ if (!SILC_ID_CLIENT_COMPARE(client_id, conn->local_id))
+ break;
+
+ /* Find Client entry and if not found query it */
+ client_entry2 =
+ silc_idlist_get_client_by_id(client, conn, client_id, TRUE);
+ if (!client_entry2) {
+ SilcPacketContext *p = silc_packet_context_dup(packet);
+ p->context = (void *)client;
+ p->sock = sock;
+ silc_client_command_pending(SILC_COMMAND_WHOIS,
+ silc_client_notify_by_server_pending, p);
+ goto out;
+ }
+
+ /* Get old Client ID */
tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
-
- /* Find channel entry */
- /* XXX this can return wrong entry */
- client_entry = silc_idlist_get_client(client, conn, tmp, NULL, 0);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find old Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ if (!client_entry)
+ goto out;
+
+ /* Remove the old from cache */
+ silc_idcache_del_by_id(conn->client_cache, SILC_ID_CLIENT,
+ client_entry->id);
+
+ /* Replace old ID entry with new one on all channels. */
+ silc_client_replace_from_channels(client, conn, client_entry,
+ client_entry2);
+
+ /* Notify application */
+ client->ops->notify(client, conn, type, client_entry, client_entry2);
+
+ /* Free data */
+ if (client_entry->nickname)
+ silc_free(client_entry->nickname);
+ if (client_entry->server)
+ silc_free(client_entry->server);
+ if (client_entry->id)
+ silc_free(client_entry->id);
+ if (client_entry->send_key)
+ silc_cipher_free(client_entry->send_key);
+ if (client_entry->receive_key)
+ silc_cipher_free(client_entry->receive_key);
+ break;
+
+ case SILC_NOTIFY_TYPE_CMODE_CHANGE:
+ /*
+ * Someone changed a channel mode
+ */
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
if (!client_entry)
+ goto out;
+
+ /* Get the mode */
+ tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ SILC_GET32_MSB(mode, tmp);
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
+ if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
+ SILC_ID_CHANNEL, &id_cache))
break;
-
- /* Get Channel ID (it's in ID payload) */
+
+ channel = (SilcChannelEntry)id_cache->context;
+
+ /* Save the new mode */
+ channel->mode = mode;
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, mode, channel);
+ break;
+
+ case SILC_NOTIFY_TYPE_CUMODE_CHANGE:
+ /*
+ * Someone changed user's mode on a channel
+ */
+
+ /* Get Client ID */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find Client entry */
+ client_entry =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ if (!client_entry)
+ goto out;
+
+ /* Get the mode */
tmp = silc_argument_get_arg_type(args, 2, &tmp_len);
- idp = silc_id_payload_parse_data(tmp, tmp_len);
- channel_id = silc_id_payload_get_id(idp);
- silc_id_payload_free(idp);
-
- /* Find channel entry */
+ if (!tmp)
+ goto out;
+
+ SILC_GET32_MSB(mode, tmp);
+
+ /* Get target Client ID */
+ tmp = silc_argument_get_arg_type(args, 3, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ silc_free(client_id);
+ client_id = silc_id_payload_parse_id(tmp, tmp_len);
+
+ /* Find target Client entry */
+ client_entry2 =
+ silc_idlist_get_client_by_id(client, conn, client_id, FALSE);
+ if (!client_entry2)
+ goto out;
+
+ /* Get channel entry */
+ channel_id = silc_id_str2id(packet->dst_id, SILC_ID_CHANNEL);
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache))
break;
-
+
channel = (SilcChannelEntry)id_cache->context;
-
- {
- SilcClientCommandContext ctx;
- char names[512];
-
- ctx = silc_calloc(1, sizeof(*ctx));
- ctx->client = client;
- ctx->conn = conn;
- ctx->command = silc_client_command_find("NAMES");
- memset(names, 0, sizeof(names));
- snprintf(names, sizeof(names), "NAMES %s", channel->channel_name);
- silc_parse_command_line(names, &ctx->argv, &ctx->argv_lens,
- &ctx->argv_types, &ctx->argc, 2);
- ctx->command->cb(ctx);
+
+ /* Save the mode */
+ for (i = 0; i < channel->clients_count; i++) {
+ if (channel->clients[i].client == client_entry2) {
+ channel->clients[i].mode = mode;
+ break;
+ }
}
+
+ /* Notify application. The channel entry is sent last as this notify
+ is for channel but application don't know it from the arguments
+ sent by server. */
+ client->ops->notify(client, conn, type, client_entry, mode,
+ client_entry2, channel);
break;
+
+ case SILC_NOTIFY_TYPE_MOTD:
+ /*
+ * Received Message of the day
+ */
+
+ /* Get motd */
+ tmp = silc_argument_get_arg_type(args, 1, &tmp_len);
+ if (!tmp)
+ goto out;
+
+ /* Notify application */
+ client->ops->notify(client, conn, type, tmp);
+ break;
+
default:
break;
}
- client->ops->notify(client, conn, payload);
+ out:
silc_notify_payload_free(payload);
if (client_id)
silc_free(client_id);
void silc_client_receive_new_id(SilcClient client,
SilcSocketConnection sock,
- unsigned char *id_string)
+ SilcIDPayload idp)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
/* Save the new ID */
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(conn->local_id_data, id_string, SILC_ID_CLIENT_LEN);
- conn->local_id_data_len = SILC_ID_CLIENT_LEN;
+
+ conn->local_id = silc_id_payload_get_id(idp);
+ conn->local_id_data = silc_id_payload_get_data(idp);
+ conn->local_id_data_len = silc_id_payload_get_len(idp);;
+
if (!conn->local_entry)
conn->local_entry = silc_calloc(1, sizeof(*conn->local_entry));
+
conn->local_entry->nickname = conn->nickname;
+ if (!conn->local_entry->username) {
+ conn->local_entry->username =
+ silc_calloc(strlen(client->username) + strlen(client->hostname) + 1,
+ sizeof(conn->local_entry->username));
+ sprintf(conn->local_entry->username, "%s@%s", client->username,
+ client->hostname);
+ }
conn->local_entry->id = conn->local_id;
/* Put it to the ID cache */
void silc_client_new_channel_id(SilcClient client,
SilcSocketConnection sock,
char *channel_name,
- unsigned int mode,
- unsigned char *id_string)
+ unsigned int mode, SilcIDPayload idp)
{
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
- SilcChannelID *id;
SilcChannelEntry channel;
SILC_LOG_DEBUG(("New channel ID"));
- id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
channel = silc_calloc(1, sizeof(*channel));
channel->channel_name = channel_name;
- channel->id = id;
+ channel->id = silc_id_payload_get_id(idp);
channel->mode = mode;
conn->current_channel = channel;
-
+
/* Put it to the ID cache */
silc_idcache_add(conn->channel_cache, channel_name, SILC_ID_CHANNEL,
- (void *)id, (void *)channel, TRUE);
+ (void *)channel->id, (void *)channel, TRUE);
}
/* Processes received key for channel. The received key will be used
SilcBuffer packet)
{
unsigned char *id_string, *key, *cipher;
- unsigned int key_len;
+ unsigned int tmp_len;
SilcClientConnection conn = (SilcClientConnection)sock->user_data;
SilcChannelID *id;
SilcIDCacheEntry id_cache = NULL;
if (!payload)
return;
- id_string = silc_channel_key_get_id(payload, NULL);
+ id_string = silc_channel_key_get_id(payload, &tmp_len);
if (!id_string) {
silc_channel_key_payload_free(payload);
return;
}
- id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
+ id = silc_id_payload_parse_id(id_string, tmp_len);
/* Find channel. */
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)id,
SILC_ID_CHANNEL, &id_cache))
goto out;
-
+
/* Save the key */
- key = silc_channel_key_get_key(payload, &key_len);
+ key = silc_channel_key_get_key(payload, &tmp_len);
cipher = silc_channel_key_get_cipher(payload, NULL);
channel = (SilcChannelEntry)id_cache->context;
- channel->key_len = key_len;
- channel->key = silc_calloc(key_len, sizeof(*channel->key));
- memcpy(channel->key, key, key_len);
+ channel->key_len = tmp_len;
+ channel->key = silc_calloc(tmp_len, sizeof(*channel->key));
+ memcpy(channel->key, key, tmp_len);
- silc_cipher_alloc(cipher, &channel->channel_key);
- if (!channel->channel_key) {
+ if (!silc_cipher_alloc(cipher, &channel->channel_key)) {
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,
- key, key_len);
+ key, tmp_len);
/* Client is now joined to the channel */
channel->on_channel = TRUE;
/* Find nickname */
nickname = "[unknown]";
for (i = 0; i < channel->clients_count; i++) {
- if (channel->clients[i] &&
- !SILC_ID_CLIENT_COMPARE(channel->clients[i]->id, client_id))
- nickname = channel->clients[i]->nickname;
+ if (channel->clients[i].client &&
+ !SILC_ID_CLIENT_COMPARE(channel->clients[i].client->id, client_id))
+ nickname = channel->clients[i].client->nickname;
}
/* Pass the message to application */
/* Allocate client entry */
remote_client = silc_calloc(1, sizeof(*remote_client));
remote_client->id = remote_id;
- remote_client->nickname = strdup(nickname);
+ silc_parse_nickname(nickname, &remote_client->nickname,
+ &remote_client->server, &remote_client->num);
/* Save the client to cache */
silc_idcache_add(conn->client_cache, remote_client->nickname,
silc_free(message);
silc_free(nickname);
}
+
+/* Removes a client entry from all channel it has joined. This really is
+ a performance killer (client_entry should have pointers to channel
+ entry list). */
+
+void silc_client_remove_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry)
+{
+ SilcIDCacheEntry id_cache;
+ SilcIDCacheList list;
+ SilcChannelEntry channel;
+ int i;
+
+ if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
+ SILC_ID_CHANNEL, &list))
+ return;
+
+ silc_idcache_list_first(list, &id_cache);
+ channel = (SilcChannelEntry)id_cache->context;
+
+ while (channel) {
+
+ /* Remove client from channel */
+ for (i = 0; i < channel->clients_count; i++) {
+ if (channel->clients[i].client == client_entry) {
+ channel->clients[i].client = NULL;
+ channel->clients_count--;
+ break;
+ }
+ }
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+
+ channel = (SilcChannelEntry)id_cache->context;
+ }
+
+ silc_idcache_list_free(list);
+}
+
+/* Replaces `old' client entries from all channels to `new' client entry.
+ This can be called for example when nickname changes and old ID entry
+ is replaced from ID cache with the new one. If the old ID entry is only
+ updated, then this fucntion needs not to be called. */
+
+void silc_client_replace_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry old,
+ SilcClientEntry new)
+{
+ SilcIDCacheEntry id_cache;
+ SilcIDCacheList list;
+ SilcChannelEntry channel;
+ int i;
+
+ if (!silc_idcache_find_by_id(conn->channel_cache, SILC_ID_CACHE_ANY,
+ SILC_ID_CHANNEL, &list))
+ return;
+
+ silc_idcache_list_first(list, &id_cache);
+ channel = (SilcChannelEntry)id_cache->context;
+
+ while (channel) {
+
+ /* Remove client from channel */
+ for (i = 0; i < channel->clients_count; i++) {
+ if (channel->clients[i].client == old) {
+ channel->clients[i].client = new;
+ break;
+ }
+ }
+
+ if (!silc_idcache_list_next(list, &id_cache))
+ break;
+
+ channel = (SilcChannelEntry)id_cache->context;
+ }
+
+ silc_idcache_list_free(list);
+}
SilcClientAway *away;
/* Pointer back to the SilcClient. This object is passed to the application
- and the actual client object is accesible thourh this pointer. */
+ and the actual client object is accesible through this pointer. */
SilcClient client;
/* User data context. Library does not touch this. */
* of this structure.
*/
- /* Users's username and realname. */
+ /* Users's username, hostname and realname. */
char *username;
+ char *hostname;
char *realname;
/* Private and public key of the user. */
SilcBuffer message);
void silc_client_notify_by_server(SilcClient client,
SilcSocketConnection sock,
- SilcBuffer message);
+ SilcPacketContext *packet);
void silc_client_receive_new_id(SilcClient client,
SilcSocketConnection sock,
- unsigned char *id_string);
+ SilcIDPayload idp);
void silc_client_new_channel_id(SilcClient client,
SilcSocketConnection sock,
char *channel_name,
- unsigned int mode,
- unsigned char *id_string);
+ unsigned int mode, SilcIDPayload idp);
void silc_client_receive_channel_key(SilcClient client,
SilcSocketConnection sock,
SilcBuffer packet);
void silc_client_private_message(SilcClient client,
SilcSocketConnection sock,
SilcPacketContext *packet);
+void silc_client_remove_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry client_entry);
+void silc_client_replace_from_channels(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientEntry old,
+ SilcClientEntry new);
#endif
SILC_CLIENT_CMD(ping, PING, "PING", SILC_CF_LAG | SILC_CF_REG, 2),
SILC_CLIENT_CMD(oper, OPER, "OPER",
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
- SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(join, JOIN, "JOIN", SILC_CF_LAG | SILC_CF_REG, 4),
SILC_CLIENT_CMD(motd, MOTD, "MOTD", SILC_CF_LAG | SILC_CF_REG, 2),
SILC_CLIENT_CMD(umode, UMODE, "UMODE", SILC_CF_LAG | SILC_CF_REG, 2),
- SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 2),
+ SILC_CLIENT_CMD(cmode, CMODE, "CMODE", SILC_CF_LAG | SILC_CF_REG, 4),
+ SILC_CLIENT_CMD(cumode, CUMODE, "CUMODE", SILC_CF_LAG | SILC_CF_REG, 5),
SILC_CLIENT_CMD(kick, KICK, "KICK", SILC_CF_LAG | SILC_CF_REG, 2),
SILC_CLIENT_CMD(restart, RESTART, "RESTART",
SILC_CF_LAG | SILC_CF_REG | SILC_CF_OPER, 2),
/* List of pending commands. */
SilcClientCommandPending *silc_command_pending = NULL;
+/* Generic function to send any command. The arguments must be sent already
+ encoded into correct form in correct order. */
+
+void silc_client_send_command(SilcClient client, SilcClientConnection conn,
+ SilcCommand command, unsigned int argc, ...)
+{
+ SilcBuffer packet;
+ va_list ap;
+
+ va_start(ap, argc);
+
+ packet = silc_command_payload_encode_vap(command, 0, argc, ap);
+ silc_client_packet_send(client, conn->sock, SILC_PACKET_COMMAND,
+ NULL, 0, NULL, NULL, packet->data,
+ packet->len, TRUE);
+ silc_buffer_free(packet);
+}
+
/* Finds and returns a pointer to the command list. Return NULL if the
command is not found. */
goto out;
}
+ if (!strncmp(conn->nickname, cmd->argv[1], cmd->argv_lens[1]))
+ goto out;
+
/* Show current nickname */
if (cmd->argc < 2) {
if (cmd->conn) {
cmd->client->ops->say(cmd->client, conn,
"Your nickname is %s", conn->nickname);
}
+
/* XXX Notify application */
COMMAND;
goto out;
SilcClientConnection conn = cmd->conn;
SilcIDCacheEntry id_cache = NULL;
SilcChannelEntry channel;
- SilcBuffer buffer;
- unsigned char *id_string;
+ SilcBuffer buffer, idp;
char *name;
if (!cmd->conn) {
channel = (SilcChannelEntry)id_cache->context;
/* Send TOPIC command to the server */
- id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
+ idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
if (cmd->argc > 2)
buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 0, 2,
- 1, id_string, SILC_ID_CHANNEL_LEN,
+ 1, idp->data, idp->len,
2, cmd->argv[2],
strlen(cmd->argv[2]));
else
buffer = silc_command_payload_encode_va(SILC_COMMAND_TOPIC, 1,
- 1, id_string, SILC_ID_CHANNEL_LEN,
+ 1, idp->data, idp->len,
0);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
+ silc_buffer_free(idp);
/* Notify application */
COMMAND;
SilcClientConnection conn = cmd->conn;
SilcClientEntry client_entry;
SilcChannelEntry channel_entry;
- SilcBuffer buffer;
+ SilcBuffer buffer, clidp, chidp;
unsigned int num = 0;
char *nickname = NULL, *server = NULL;
- unsigned char *client_id, *channel_id;
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
/* Find client entry */
client_entry = silc_idlist_get_client(client, conn, nickname, server, num);
if (!client_entry) {
+ if (nickname)
+ silc_free(nickname);
+ if (server)
+ silc_free(server);
+
/* Client entry not found, it was requested thus mark this to be
pending command. */
silc_client_command_pending(SILC_COMMAND_IDENTIFY,
silc_client_command_invite, context);
return;
}
-
- client_id = silc_id_id2str(client_entry->id, SILC_ID_CLIENT);
/* Find channel entry */
channel_entry = silc_idlist_get_channel(client, conn, cmd->argv[2]);
if (!channel_entry) {
cmd->client->ops->say(cmd->client, conn, "You are not on that channel");
- silc_free(client_id);
COMMAND_ERROR;
goto out;
}
- channel_id = silc_id_id2str(channel_entry->id, SILC_ID_CHANNEL);
-
+ /* Send command */
+ clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+ chidp = silc_id_payload_encode(channel_entry->id, SILC_ID_CHANNEL);
buffer = silc_command_payload_encode_va(SILC_COMMAND_INVITE, 0, 2,
- 1, client_id, SILC_ID_CLIENT_LEN,
- 2, channel_id, SILC_ID_CHANNEL_LEN);
+ 1, clidp->data, clidp->len,
+ 2, chidp->data, chidp->len);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
+ silc_buffer_free(clidp);
+ silc_buffer_free(chidp);
cmd->client->ops->say(cmd->client, conn,
"Inviting %s to channel %s", cmd->argv[1],
if (cmd->argc == 1 || !strcmp(cmd->argv[1], conn->remote_host))
name = strdup(conn->remote_host);
- id = silc_id_str2id(conn->remote_id_data, SILC_ID_SERVER);
-
/* Send the command */
buffer = silc_command_payload_encode_va(SILC_COMMAND_PING, 0, 1,
1, conn->remote_id_data,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
+ id = silc_id_str2id(conn->remote_id_data, SILC_ID_SERVER);
+
/* Start counting time */
for (i = 0; i < conn->ping_count; i++) {
if (conn->ping[i].dest_id == NULL) {
}
/* Send JOIN command to the server */
- buffer = silc_command_payload_encode(SILC_COMMAND_JOIN,
- cmd->argc - 1, ++cmd->argv,
- ++cmd->argv_lens, ++cmd->argv_types, 0);
+ if (cmd->argc == 2)
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 1,
+ 1, cmd->argv[1], cmd->argv_lens[1]);
+ else if (cmd->argc == 3)
+ /* XXX Buggy */
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 2,
+ 1, cmd->argv[1], cmd->argv_lens[1],
+ 2, cmd->argv[2], cmd->argv_lens[2]);
+ else
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_JOIN, 0, 3,
+ 1, cmd->argv[1], cmd->argv_lens[1],
+ 2, cmd->argv[2], cmd->argv_lens[2],
+ 3, cmd->argv[3], cmd->argv_lens[3]);
+
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- cmd->argv--;
- cmd->argv_lens--;
- cmd->argv_types--;
/* Notify application */
COMMAND;
silc_client_command_free(cmd);
}
+/* MOTD command. Requests motd from server. */
+
SILC_CLIENT_CMD_FUNC(motd)
{
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
silc_client_command_free(cmd);
}
+/* UMODE. Set user mode in SILC. */
+
SILC_CLIENT_CMD_FUNC(umode)
{
+
}
+/* CMODE command. Sets channel mode. Modes that does not require any arguments
+ can be set several at once. Those modes that require argument must be set
+ separately (unless set with modes that does not require arguments). */
+
SILC_CLIENT_CMD_FUNC(cmode)
{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcChannelEntry channel;
+ SilcBuffer buffer, chidp;
+ unsigned char *name, *cp, modebuf[4], tmp[4], *arg = NULL;
+ unsigned int mode, add, type, len, arg_len = 0;
+ int i;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argc < 3) {
+ cmd->client->ops->say(cmd->client, conn,
+ "Usage: /CMODE <channel> +|-<modes> [{ <arguments>}]");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argv[1][0] == '*') {
+ if (!conn->current_channel) {
+ cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ channel = conn->current_channel;
+ } else {
+ name = cmd->argv[1];
+
+ channel = silc_idlist_get_channel(cmd->client, conn, name);
+ if (!channel) {
+ cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+ COMMAND_ERROR;
+ goto out;
+ }
+ }
+
+ mode = channel->mode;
+
+ /* Are we adding or removing mode */
+ if (cmd->argv[2][0] == '-')
+ add = FALSE;
+ else
+ add = TRUE;
+
+ /* Argument type to be sent to server */
+ type = 0;
+
+ /* Parse mode */
+ cp = cmd->argv[2] + 1;
+ len = strlen(cp);
+ for (i = 0; i < len; i++) {
+ switch(cp[i]) {
+ case 'p':
+ if (add)
+ mode |= SILC_CHANNEL_MODE_PRIVATE;
+ else
+ mode &= ~SILC_CHANNEL_MODE_PRIVATE;
+ break;
+ case 's':
+ if (add)
+ mode |= SILC_CHANNEL_MODE_SECRET;
+ else
+ mode &= ~SILC_CHANNEL_MODE_SECRET;
+ break;
+ case 'k':
+ if (add)
+ mode |= SILC_CHANNEL_MODE_PRIVKEY;
+ else
+ mode &= ~SILC_CHANNEL_MODE_PRIVKEY;
+ break;
+ case 'i':
+ if (add)
+ mode |= SILC_CHANNEL_MODE_INVITE;
+ else
+ mode &= ~SILC_CHANNEL_MODE_INVITE;
+ break;
+ case 't':
+ if (add)
+ mode |= SILC_CHANNEL_MODE_TOPIC;
+ else
+ mode &= ~SILC_CHANNEL_MODE_TOPIC;
+ break;
+ case 'l':
+ if (add) {
+ int ll;
+ mode |= SILC_CHANNEL_MODE_ULIMIT;
+ type = 3;
+ ll = atoi(cmd->argv[3]);
+ SILC_PUT32_MSB(ll, tmp);
+ arg = tmp;
+ arg_len = 4;
+ } else {
+ mode &= ~SILC_CHANNEL_MODE_ULIMIT;
+ }
+ break;
+ case 'a':
+ if (add) {
+ mode |= SILC_CHANNEL_MODE_PASSPHRASE;
+ type = 4;
+ arg = cmd->argv[3];
+ arg_len = cmd->argv_lens[3];
+ } else {
+ mode &= ~SILC_CHANNEL_MODE_PASSPHRASE;
+ }
+ break;
+ case 'b':
+ if (add) {
+ mode |= SILC_CHANNEL_MODE_BAN;
+ type = 5;
+ arg = cmd->argv[3];
+ arg_len = cmd->argv_lens[3];
+ } else {
+ mode &= ~SILC_CHANNEL_MODE_BAN;
+ }
+ break;
+ case 'I':
+ if (add) {
+ mode |= SILC_CHANNEL_MODE_INVITE_LIST;
+ type = 6;
+ arg = cmd->argv[3];
+ arg_len = cmd->argv_lens[3];
+ } else {
+ mode &= ~SILC_CHANNEL_MODE_INVITE_LIST;
+ }
+ break;
+ case 'c':
+ if (add) {
+ mode |= SILC_CHANNEL_MODE_CIPHER;
+ type = 8;
+ arg = cmd->argv[3];
+ arg_len = cmd->argv_lens[3];
+ } else {
+ mode &= ~SILC_CHANNEL_MODE_CIPHER;
+ }
+ break;
+ default:
+ COMMAND_ERROR;
+ goto out;
+ break;
+ }
+ }
+
+ if (type && cmd->argc < 3) {
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ SILC_PUT32_MSB(mode, modebuf);
+
+ /* Send the command packet. We support sending only one mode at once
+ that requires an argument. */
+ if (type && arg) {
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 3,
+ 1, chidp->data, chidp->len,
+ 2, modebuf, sizeof(modebuf),
+ type, arg, arg_len);
+ } else {
+ buffer =
+ silc_command_payload_encode_va(SILC_COMMAND_CMODE, 0, 2,
+ 1, chidp->data, chidp->len,
+ 2, modebuf, sizeof(modebuf));
+ }
+
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(chidp);
+
+ /* Notify application */
+ COMMAND;
+
+ out:
+ silc_client_command_free(cmd);
+}
+
+/* CUMODE command. Changes client's mode on a channel. */
+
+SILC_CLIENT_CMD_FUNC(cumode)
+{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+ SilcChannelEntry channel;
+ SilcClientEntry client_entry;
+ SilcBuffer buffer, clidp, chidp;
+ unsigned char *name, *cp, modebuf[4];
+ unsigned int mode = 0, add, len;
+ char *nickname = NULL, *server = NULL;
+ unsigned int num = 0;
+ int i;
+
+ if (!cmd->conn) {
+ SILC_NOT_CONNECTED(cmd->client, cmd->conn);
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argc < 4) {
+ cmd->client->ops->say(cmd->client, conn,
+ "Usage: /CUMODE <channel> +|-<modes> <nickname>[@<server>]");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ if (cmd->argv[1][0] == '*') {
+ if (!conn->current_channel) {
+ cmd->client->ops->say(cmd->client, conn, "You are not on any channel");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ channel = conn->current_channel;
+ } else {
+ name = cmd->argv[1];
+
+ channel = silc_idlist_get_channel(cmd->client, conn, name);
+ if (!channel) {
+ cmd->client->ops->say(cmd->client, conn, "You are on that channel");
+ COMMAND_ERROR;
+ goto out;
+ }
+ }
+
+ /* Parse the typed nickname. */
+ if (!silc_parse_nickname(cmd->argv[3], &nickname, &server, &num)) {
+ cmd->client->ops->say(cmd->client, conn, "Bad nickname");
+ COMMAND_ERROR;
+ goto out;
+ }
+
+ /* Find client entry */
+ client_entry = silc_idlist_get_client(cmd->client, conn,
+ nickname, server, num);
+ if (!client_entry) {
+ /* Client entry not found, it was requested thus mark this to be
+ pending command. */
+ silc_client_command_pending(SILC_COMMAND_CUMODE,
+ silc_client_command_cumode, context);
+ return;
+ }
+
+ for (i = 0; i < channel->clients_count; i++)
+ if (channel->clients[i].client == client_entry) {
+ mode = channel->clients[i].mode;
+ break;
+ }
+
+ /* Are we adding or removing mode */
+ if (cmd->argv[2][0] == '-')
+ add = FALSE;
+ else
+ add = TRUE;
+
+ /* Parse mode */
+ cp = cmd->argv[2] + 1;
+ len = strlen(cp);
+ for (i = 0; i < len; i++) {
+ switch(cp[i]) {
+ case 'a':
+ if (add) {
+ mode |= SILC_CHANNEL_UMODE_CHANFO;
+ mode |= SILC_CHANNEL_UMODE_CHANOP;
+ } else {
+ mode = SILC_CHANNEL_UMODE_NONE;
+ }
+ break;
+ case 'f':
+ if (add)
+ mode |= SILC_CHANNEL_UMODE_CHANFO;
+ else
+ mode &= ~SILC_CHANNEL_UMODE_CHANFO;
+ break;
+ case 'o':
+ if (add)
+ mode |= SILC_CHANNEL_UMODE_CHANOP;
+ else
+ mode &= ~SILC_CHANNEL_UMODE_CHANOP;
+ break;
+ default:
+ COMMAND_ERROR;
+ goto out;
+ break;
+ }
+ }
+
+ chidp = silc_id_payload_encode(channel->id, SILC_ID_CHANNEL);
+ SILC_PUT32_MSB(mode, modebuf);
+ clidp = silc_id_payload_encode(client_entry->id, SILC_ID_CLIENT);
+
+ /* Send the command packet. We support sending only one mode at once
+ that requires an argument. */
+ buffer = silc_command_payload_encode_va(SILC_COMMAND_CUMODE, 0, 3,
+ 1, chidp->data, chidp->len,
+ 2, modebuf, 4,
+ 3, clidp->data, clidp->len);
+
+ silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
+ 0, NULL, NULL, buffer->data, buffer->len, TRUE);
+ silc_buffer_free(buffer);
+ silc_buffer_free(chidp);
+ silc_buffer_free(clidp);
+
+ /* Notify application */
+ COMMAND;
+
+ out:
+ silc_client_command_free(cmd);
}
+/* KICK command. Kicks a client out of channel. */
+
SILC_CLIENT_CMD_FUNC(kick)
{
+ SilcClientCommandContext cmd = (SilcClientCommandContext)context;
+ SilcClientConnection conn = cmd->conn;
+
}
SILC_CLIENT_CMD_FUNC(restart)
SilcClientConnection conn = cmd->conn;
SilcIDCacheEntry id_cache = NULL;
SilcChannelEntry channel;
- SilcBuffer buffer;
- unsigned char *id_string;
+ SilcBuffer buffer, idp;
char *name;
if (!cmd->conn) {
channel = (SilcChannelEntry)id_cache->context;
/* Send LEAVE command to the server */
- id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
+ idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
buffer = silc_command_payload_encode_va(SILC_COMMAND_LEAVE, 0, 1,
- 1, id_string, SILC_ID_CHANNEL_LEN);
+ 1, idp->data, idp->len);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
+ silc_buffer_free(idp);
/* We won't talk anymore on this channel */
cmd->client->ops->say(cmd->client, conn, "You have left channel %s", name);
silc_free(channel->key);
silc_cipher_free(channel->channel_key);
silc_free(channel);
- silc_free(id_string);
/* Notify application */
COMMAND;
SilcClientCommandContext cmd = (SilcClientCommandContext)context;
SilcClientConnection conn = cmd->conn;
SilcIDCacheEntry id_cache = NULL;
- SilcBuffer buffer;
+ SilcBuffer buffer, idp;
char *name;
- unsigned char *id_string;
if (!cmd->conn) {
SILC_NOT_CONNECTED(cmd->client, cmd->conn);
}
/* Send NAMES command to the server */
- id_string = silc_id_id2str(id_cache->id, SILC_ID_CHANNEL);
+ idp = silc_id_payload_encode(id_cache->id, SILC_ID_CHANNEL);
buffer = silc_command_payload_encode_va(SILC_COMMAND_NAMES, 0, 1,
- 1, id_string, SILC_ID_CHANNEL_LEN);
+ 1, idp->data, idp->len);
silc_client_packet_send(cmd->client, conn->sock, SILC_PACKET_COMMAND, NULL,
0, NULL, NULL, buffer->data, buffer->len, TRUE);
silc_buffer_free(buffer);
- silc_free(id_string);
+ silc_buffer_free(idp);
/* Register dummy pending command that will tell the reply command
that user called this command. Server may send reply to this command
even if user did not send this command thus we want to handle things
differently when user sent the command. This is dummy and won't be
- execute. */
+ executed. */
/* XXX this is kludge and should be removed after pending command reply
support is added. Currently only commands may be pending not command
replies. */
/* Prototypes */
void silc_client_command_free(SilcClientCommandContext cmd);
+void silc_client_send_command(SilcClient client, SilcClientConnection conn,
+ SilcCommand command, unsigned int argc, ...);
SilcClientCommand *silc_client_command_find(const char *name);
void silc_client_command_pending(SilcCommand reply_cmd,
SilcClientCommandCallback callback,
SILC_CLIENT_CMD_FUNC(motd);
SILC_CLIENT_CMD_FUNC(umode);
SILC_CLIENT_CMD_FUNC(cmode);
+SILC_CLIENT_CMD_FUNC(cumode);
SILC_CLIENT_CMD_FUNC(kick);
SILC_CLIENT_CMD_FUNC(restart);
SILC_CLIENT_CMD_FUNC(close);
/*
* Command reply functions are "the otherside" of the command functions.
* Reply to a command sent by server is handled by these functions.
+ *
+ * The arguments received from server are also passed to the calling
+ * application through command_reply client operation. The arguments are
+ * exactly same and in same order as the server sent it. However, ID's are
+ * not sent to the application. Instead, corresponding ID entry is sent
+ * to the application. For example, instead of sending Client ID the
+ * corresponding SilcClientEntry is sent to the application. The case is
+ * same with for example Channel ID's. This way application has all the
+ * necessary data already in hand without redundant searching. If ID is
+ * received but ID entry does not exist, NULL is sent.
*/
/* $Id$ */
SILC_CLIENT_CMD_REPLY(motd, MOTD),
SILC_CLIENT_CMD_REPLY(umode, UMODE),
SILC_CLIENT_CMD_REPLY(cmode, CMODE),
+ SILC_CLIENT_CMD_REPLY(cumode, CUMODE),
SILC_CLIENT_CMD_REPLY(kick, KICK),
SILC_CLIENT_CMD_REPLY(restart, RESTART),
SILC_CLIENT_CMD_REPLY(close, CLOSE),
{ STAT(NO_SUCH_CHANNEL_ID),"No such Channel ID" },
{ STAT(NICKNAME_IN_USE), "Nickname already exists" },
{ STAT(NOT_ON_CHANNEL), "You are not on that channel" },
- { STAT(USER_ON_CHANNEL), "User already on channel" },
+ { STAT(USER_NOT_ON_CHANNEL),"They are not on the channel" },
+ { STAT(USER_ON_CHANNEL), "User already on the channel" },
{ STAT(NOT_REGISTERED), "You have not registered" },
{ STAT(NOT_ENOUGH_PARAMS), "Not enough parameters" },
{ STAT(TOO_MANY_PARAMS), "Too many parameters" },
Usage: COMMAND_REPLY((ARGS, argument1, argument2, etc...)), */
#define COMMAND_REPLY(args) cmd->client->ops->command_reply args
#define ARGS cmd->client, cmd->sock->user_data, \
- cmd->payload, TRUE, status, silc_command_get(cmd->payload)
+ cmd->payload, TRUE, silc_command_get(cmd->payload), status
/* Error reply to application. Usage: COMMAND_REPLY_ERROR; */
#define COMMAND_REPLY_ERROR cmd->client->ops->command_reply(cmd->client, \
- cmd->sock->user_data, cmd->payload, FALSE, status, \
- silc_command_get(cmd->payload))
+ cmd->sock->user_data, cmd->payload, FALSE, \
+ silc_command_get(cmd->payload), status)
/* Process received command reply. */
unsigned char *id_data;
char *nickname = NULL, *username = NULL;
char *realname = NULL;
+ SilcClientID *client_id;
+ SilcIDCacheEntry id_cache = NULL;
+ SilcClientEntry client_entry = NULL;
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
memset(buf, 0, sizeof(buf));
argc = silc_argument_get_arg_num(cmd->args);
- id_data = silc_argument_get_arg_type(cmd->args, 2, NULL);
+
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!id_data) {
+ COMMAND_REPLY_ERROR;
+ return;
+ }
+
+ client_id = silc_id_payload_parse_id(id_data, len);
nickname = silc_argument_get_arg_type(cmd->args, 3, &len);
if (nickname) {
strncat(buf, ")", 1);
}
- cmd->client->ops->say(cmd->client, conn, "%s", buf);
-
+ /* Check if we have this client cached already. */
+ if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
+ SILC_ID_CLIENT, &id_cache)) {
+ client_entry = silc_calloc(1, sizeof(*client_entry));
+ client_entry->id = client_id;
+ silc_parse_nickname(nickname, &client_entry->nickname,
+ &client_entry->server, &client_entry->num);
+ client_entry->username = strdup(username);
+
+ /* Add client to cache */
+ silc_idcache_add(conn->client_cache, client_entry->nickname,
+ SILC_ID_CLIENT, client_id, (void *)client_entry, TRUE);
+ } else {
+ client_entry = (SilcClientEntry)id_cache->context;
+ silc_free(client_id);
+ }
+
+ if (!cmd->callback)
+ cmd->client->ops->say(cmd->client, conn, "%s", buf);
+
/* Notify application */
- COMMAND_REPLY((ARGS));
+ COMMAND_REPLY((ARGS, client_entry, nickname,
+ username, realname, NULL, NULL));
}
/* Received reply for WHOIS command. This maybe called several times
for one WHOIS command as server may reply with list of results. */
-/* Sends to application: (no arguments) */
SILC_CLIENT_CMD_REPLY_FUNC(whois)
{
silc_client_command_reply_free(cmd);
}
+/* Received reply for WHOWAS command. */
+
SILC_CLIENT_CMD_REPLY_FUNC(whowas)
{
+
}
/* Received reply for IDENTIFY command. This maybe called several times
/* Display one whois reply */
if (status == SILC_STATUS_OK) {
+ unsigned int len;
unsigned char *id_data;
char *nickname;
+ char *username;
- id_data = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ id_data = silc_argument_get_arg_type(cmd->args, 2, &len);
nickname = silc_argument_get_arg_type(cmd->args, 3, NULL);
+ username = silc_argument_get_arg_type(cmd->args, 4, NULL);
/* Allocate client entry */
client_entry = silc_calloc(1, sizeof(*client_entry));
- client_entry->id = silc_id_str2id(id_data, SILC_ID_CLIENT);
- client_entry->nickname = strdup(nickname);
+ client_entry->id = silc_id_payload_parse_id(id_data, len);
+ if (nickname)
+ silc_parse_nickname(nickname, &client_entry->nickname,
+ &client_entry->server, &client_entry->num);
+ if (username)
+ client_entry->username = strdup(username);
/* Save received Client ID to ID cache */
silc_idcache_add(conn->client_cache, client_entry->nickname,
/* Received reply for command NICK. If everything went without errors
we just received our new Client ID. */
-/* Sends to application: char * (nickname). */
SILC_CLIENT_CMD_REPLY_FUNC(nick)
{
SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcCommandStatus status;
- unsigned char *tmp, *id_string;
- int argc;
+ SilcIDPayload idp;
+ unsigned char *tmp;
+ unsigned int argc, len;
SILC_LOG_DEBUG(("Start"));
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
- SILC_GET16_MSB(status, tmp);
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
cmd->client->ops->say(cmd->client, conn, "Cannot set nickname: %s",
silc_client_command_status_message(status));
}
/* Take received Client ID */
- id_string = silc_argument_get_arg_type(cmd->args, 2, NULL);
- silc_client_receive_new_id(cmd->client, cmd->sock, id_string);
-
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ idp = silc_id_payload_parse_data(tmp, len);
+ silc_client_receive_new_id(cmd->client, cmd->sock, idp);
+
/* Notify application */
- COMMAND_REPLY((ARGS, conn->nickname));
+ COMMAND_REPLY((ARGS, conn->local_entry));
out:
silc_client_command_reply_free(cmd);
}
/* Received reply to topic command. */
-/* Sends to application: SilcChannelID * (channel_id) and char * (topic) */
SILC_CLIENT_CMD_REPLY_FUNC(topic)
{
SilcChannelEntry channel;
SilcChannelID *channel_id = NULL;
SilcIDCacheEntry id_cache = NULL;
- unsigned char *tmp, *id_string;
+ unsigned char *tmp;
char *topic;
- int argc;
+ unsigned int argc, len;
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
- SILC_GET16_MSB(status, tmp);
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
cmd->client->ops->say(cmd->client, conn,
"%s", silc_client_command_status_message(status));
- silc_client_command_reply_free(cmd);
COMMAND_REPLY_ERROR;
+ silc_client_command_reply_free(cmd);
return;
}
}
/* Take Channel ID */
- id_string = silc_argument_get_arg_type(cmd->args, 2, NULL);
- if (!id_string)
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len);
+ if (!tmp)
goto out;
- channel_id = silc_id_str2id(id_string, SILC_ID_CHANNEL);
-
/* Take topic */
topic = silc_argument_get_arg_type(cmd->args, 3, NULL);
if (!topic)
goto out;
+ channel_id = silc_id_payload_parse_id(tmp, len);
+
/* Get the channel name */
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache)) {
+ silc_free(channel_id);
COMMAND_REPLY_ERROR;
goto out;
}
topic);
/* Notify application */
- COMMAND_REPLY((ARGS, channel_id, topic));
+ COMMAND_REPLY((ARGS, channel, topic));
out:
- if (channel_id)
- silc_free(channel_id);
silc_client_command_reply_free(cmd);
}
/* Received reply to invite command. */
-/* Sends to application: (no arguments) */
SILC_CLIENT_CMD_REPLY_FUNC(invite)
{
if (status != SILC_STATUS_OK) {
cmd->client->ops->say(cmd->client, conn,
"%s", silc_client_command_status_message(status));
- silc_client_command_reply_free(cmd);
COMMAND_REPLY_ERROR;
+ silc_client_command_reply_free(cmd);
return;
}
/* Received reply to INFO command. We receive the server ID and some
information about the server user requested. */
-/* Sends to application: char * (server information) */
SILC_CLIENT_CMD_REPLY_FUNC(info)
{
if (status != SILC_STATUS_OK) {
cmd->client->ops->say(cmd->client, conn,
"%s", silc_client_command_status_message(status));
- silc_client_command_reply_free(cmd);
COMMAND_REPLY_ERROR;
+ silc_client_command_reply_free(cmd);
return;
}
client->ops->say(cmd->client, conn, "Info: %s", tmp);
/* Notify application */
- COMMAND_REPLY((ARGS, (char *)tmp));
+ COMMAND_REPLY((ARGS, NULL, (char *)tmp));
out:
silc_client_command_reply_free(cmd);
}
/* Received reply to PING command. The reply time is shown to user. */
-/* Sends to application: (no arguments) */
SILC_CLIENT_CMD_REPLY_FUNC(ping)
{
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcCommandStatus status;
void *id;
- char *tmp;
int i;
time_t diff, curtime;
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
- SILC_GET16_MSB(status, tmp);
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
cmd->client->ops->say(cmd->client, conn,
"%s", silc_client_command_status_message(status));
/* Notify application */
COMMAND_REPLY((ARGS));
- goto out;
+ break;
}
}
+ silc_free(id);
+
out:
silc_client_command_reply_free(cmd);
}
SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
SilcClient client = cmd->client;
SilcCommandStatus status;
- unsigned int argc, mode;
- unsigned char *id_string;
+ SilcIDPayload idp;
+ unsigned int argc, mode, len;
char *topic, *tmp, *channel_name;
SILC_LOG_DEBUG(("Start"));
- tmp = silc_argument_get_arg_type(cmd->args, 1, NULL);
- SILC_GET16_MSB(status, tmp);
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
if (status != SILC_STATUS_OK) {
cmd->client->ops->say(cmd->client, conn,
"%s", silc_client_command_status_message(status));
channel_name = strdup(tmp);
/* Get Channel ID */
- id_string = silc_argument_get_arg_type(cmd->args, 3, NULL);
- if (!id_string) {
+ tmp = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (!tmp) {
cmd->client->ops->say(cmd->client, conn,
"Cannot join channel: Bad reply packet");
COMMAND_REPLY_ERROR;
goto out;
}
+ idp = silc_id_payload_parse_data(tmp, len);
/* Get channel mode */
tmp = silc_argument_get_arg_type(cmd->args, 4, NULL);
/* Save received Channel ID */
silc_client_new_channel_id(cmd->client, cmd->sock, channel_name,
- mode, id_string);
+ mode, idp);
+ silc_id_payload_free(idp);
if (topic)
client->ops->say(cmd->client, conn,
"Topic for %s: %s", channel_name, topic);
/* Notify application */
- COMMAND_REPLY((ARGS, channel_name, topic));
+ COMMAND_REPLY((ARGS, channel_name, conn->current_channel, mode,
+ NULL, NULL, topic));
out:
silc_client_command_reply_free(cmd);
}
/* Received reply for MOTD command */
-/* Sends to application: char * (motd) */
SILC_CLIENT_CMD_REPLY_FUNC(motd)
{
{
}
+/* Received reply for CMODE command. */
+
SILC_CLIENT_CMD_REPLY_FUNC(cmode)
{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcCommandStatus status;
+ unsigned char *tmp;
+
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+ if (status != SILC_STATUS_OK) {
+ cmd->client->ops->say(cmd->client, conn,
+ "%s", silc_client_command_status_message(status));
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Get channel mode */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Notify application */
+ COMMAND_REPLY((ARGS, tmp));
+
+ out:
+ silc_client_command_reply_free(cmd);
+}
+
+/* Received reply for CUMODE command */
+
+SILC_CLIENT_CMD_REPLY_FUNC(cumode)
+{
+ SilcClientCommandReplyContext cmd = (SilcClientCommandReplyContext)context;
+ SilcClientConnection conn = (SilcClientConnection)cmd->sock->user_data;
+ SilcCommandStatus status;
+ SilcIDCacheEntry id_cache = NULL;
+ SilcClientID *client_id;
+ unsigned char *tmp, *id;
+ unsigned int len;
+
+ SILC_GET16_MSB(status, silc_argument_get_arg_type(cmd->args, 1, NULL));
+ if (status != SILC_STATUS_OK) {
+ cmd->client->ops->say(cmd->client, conn,
+ "%s", silc_client_command_status_message(status));
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Get channel mode */
+ tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ if (!tmp) {
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Get Client ID */
+ id = silc_argument_get_arg_type(cmd->args, 3, &len);
+ if (!id) {
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+ client_id = silc_id_payload_parse_id(id, len);
+
+ /* Get client entry */
+ if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
+ SILC_ID_CLIENT, &id_cache)) {
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ /* Notify application */
+ COMMAND_REPLY((ARGS, tmp, (SilcClientEntry)id_cache->context));
+ silc_free(client_id);
+
+ out:
+ silc_client_command_reply_free(cmd);
}
SILC_CLIENT_CMD_REPLY_FUNC(kick)
}
/* Reply to LEAVE command. */
-/* Sends to application: (no arguments) */
SILC_CLIENT_CMD_REPLY_FUNC(leave)
{
SilcChannelEntry channel;
SilcChannelID *channel_id = NULL;
SilcBuffer client_id_list;
+ SilcBuffer client_mode_list;
unsigned char *tmp;
char *name_list, *cp;
int i, k, len1, len2, list_count = 0;
}
/* Get channel ID */
- tmp = silc_argument_get_arg_type(cmd->args, 2, NULL);
+ tmp = silc_argument_get_arg_type(cmd->args, 2, &len1);
if (!tmp) {
cmd->client->ops->say(cmd->client, conn,
- "Cannot get user list: Bad reply packet");
+ "Cannot Channel ID: Bad reply packet");
COMMAND_REPLY_ERROR;
goto out;
}
- channel_id = silc_id_str2id(tmp, SILC_ID_CHANNEL);
+ channel_id = silc_id_payload_parse_id(tmp, len1);
/* Get the name list of the channel */
name_list = silc_argument_get_arg_type(cmd->args, 3, &len1);
silc_buffer_pull_tail(client_id_list, len2);
silc_buffer_put(client_id_list, tmp, len2);
+ /* Get client mode list */
+ tmp = silc_argument_get_arg_type(cmd->args, 5, &len2);
+ if (!tmp) {
+ cmd->client->ops->say(cmd->client, conn,
+ "Cannot get user list: Bad reply packet");
+ COMMAND_REPLY_ERROR;
+ goto out;
+ }
+
+ client_mode_list = silc_buffer_alloc(len2);
+ silc_buffer_pull_tail(client_mode_list, len2);
+ silc_buffer_put(client_mode_list, tmp, len2);
+
/* Get the channel name */
if (!silc_idcache_find_by_id_one(conn->channel_cache, (void *)channel_id,
SILC_ID_CHANNEL, &id_cache)) {
/* Allocate room for clients in the channel */
channel->clients = silc_calloc(list_count, sizeof(*channel->clients));
- /* Cache the received name list and client ID's. This cache expires
+ /* Cache the received name list, client ID's and modes. This cache expires
whenever server sends notify message to channel. It means two things;
some user has joined or leaved the channel. */
cp = name_list;
for (i = 0; i < list_count; i++) {
int nick_len = strcspn(name_list, " ");
- char *nickname = silc_calloc(nick_len, sizeof(*nickname));
+ unsigned short idp_len;
+ unsigned int mode;
+ char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
SilcClientID *client_id;
SilcClientEntry client;
memcpy(nickname, name_list, nick_len);
- client_id = silc_id_str2id(client_id_list->data, SILC_ID_CLIENT);
- silc_buffer_pull(client_id_list, SILC_ID_CLIENT_LEN);
+ SILC_GET16_MSB(idp_len, client_id_list->data + 2);
+ idp_len += 4;
+ client_id = silc_id_payload_parse_id(client_id_list->data, idp_len);
+ silc_buffer_pull(client_id_list, idp_len);
+
+ SILC_GET32_MSB(mode, client_mode_list->data);
+ silc_buffer_pull(client_mode_list, 4);
/* Check if we have this client cached already. */
if (!silc_idcache_find_by_id_one(conn->client_cache, (void *)client_id,
SILC_ID_CLIENT, &id_cache)) {
client = silc_calloc(1, sizeof(*client));
client->id = client_id;
- client->nickname = nickname;
+ silc_parse_nickname(nickname, &client->nickname, &client->server,
+ &client->num);
+ silc_free(nickname);
/* Add client to cache */
- silc_idcache_add(conn->client_cache, nickname, SILC_ID_CLIENT,
+ silc_idcache_add(conn->client_cache, client->nickname, SILC_ID_CLIENT,
client_id, (void *)client, TRUE);
} else {
client = (SilcClientEntry)id_cache->context;
id_cache = NULL;
}
- channel->clients[channel->clients_count] = client;
+ channel->clients[channel->clients_count].client = client;
+ channel->clients[channel->clients_count].mode = mode;
channel->clients_count++;
name_list += nick_len + 1;
for (i = 0; i < list_count; i++) {
int c;
int nick_len = strcspn(name_list, " ");
- char *nickname = silc_calloc(nick_len, sizeof(*nickname));
+ char *nickname = silc_calloc(nick_len + 1, sizeof(*nickname));
memcpy(nickname, name_list, nick_len);
for (c = 0, k = 0; k < channel->clients_count; k++) {
- if (channel->clients[k] &&
- !strncmp(channel->clients[k]->nickname,
- nickname, strlen(channel->clients[k]->nickname))) {
+ if (channel->clients[k].client &&
+ !strncmp(channel->clients[k].client->nickname,
+ nickname, strlen(channel->clients[k].client->nickname))) {
char t[8];
if (!c) {
}
memset(t, 0, sizeof(t));
- channel->clients[k]->nickname =
- silc_calloc(strlen(nickname) + 8,
- sizeof(*channel->clients[k]->nickname));
- strncat(channel->clients[k]->nickname, nickname, strlen(nickname));
+ channel->clients[k].client->nickname =
+ silc_calloc(strlen(nickname) + 8, sizeof(*channel->clients[k].
+ client->nickname));
+ strncat(channel->clients[k].client->nickname, nickname,
+ strlen(nickname));
snprintf(t, sizeof(t), " [%d]", c++);
- strncat(channel->clients[k]->nickname, t, strlen(t));
+ strncat(channel->clients[k].client->nickname, t, strlen(t));
}
}
name_list = NULL;
len1 = 0;
for (k = 0; k < channel->clients_count; k++) {
- char *n = channel->clients[k]->nickname;
+ char *n = channel->clients[k].client->nickname;
len2 = strlen(n);
len1 += len2;
name_list = silc_realloc(name_list, sizeof(*name_list) * (len1 + 1));
cmd->client->ops->say(cmd->client, conn,
"Users on %s: %s", channel->channel_name, name_list);
+ /* Notify application */
+ COMMAND_REPLY((ARGS, channel, name_list, client_id_list->head,
+ client_mode_list->head));
+
silc_free(name_list);
silc_buffer_free(client_id_list);
+ silc_buffer_free(client_mode_list);
out:
if (channel_id)
SILC_CLIENT_CMD_REPLY_FUNC(motd);
SILC_CLIENT_CMD_REPLY_FUNC(umode);
SILC_CLIENT_CMD_REPLY_FUNC(cmode);
+SILC_CLIENT_CMD_REPLY_FUNC(cumode);
SILC_CLIENT_CMD_REPLY_FUNC(kick);
SILC_CLIENT_CMD_REPLY_FUNC(restart);
SILC_CLIENT_CMD_REPLY_FUNC(close);
entry = (SilcClientEntry)id_cache->context;
} else {
/* Check multiple cache entries for match */
- while (silc_idcache_list_next(list, &id_cache)) {
- entry = (SilcClientEntry)id_cache->context;
-
+ silc_idcache_list_first(list, &id_cache);
+ entry = (SilcClientEntry)id_cache->context;
+
+ while (entry) {
if (server && entry->server &&
- strncasecmp(server, entry->server, strlen(server))) {
- entry = NULL;
- continue;
- }
+ !strncasecmp(server, entry->server, strlen(server)))
+ break;
- if (num && entry->num != num) {
+ if (num && entry->num == num)
+ break;
+
+ if (!silc_idcache_list_next(list, &id_cache)) {
entry = NULL;
- continue;
+ break;
}
- break;
+ entry = (SilcClientEntry)id_cache->context;
}
/* If match weren't found, request it */
return entry;
}
+/* Finds client entry from cache by Client ID. If the entry is not found
+ from the cache this function can query it from the server. */
+
+SilcClientEntry silc_idlist_get_client_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientID *client_id,
+ int query)
+{
+ SilcIDCacheEntry id_cache;
+
+ /* Find ID from cache */
+ if (!silc_idcache_find_by_id_one(conn->client_cache, client_id,
+ SILC_ID_CLIENT, &id_cache)) {
+ if (!query) {
+ return NULL;
+ } else {
+ SilcBuffer idp = silc_id_payload_encode(client_id, SILC_ID_CLIENT);
+ silc_client_send_command(client, conn, SILC_COMMAND_WHOIS, 1,
+ 2, idp->data, idp->len);
+ return NULL;
+ }
+ }
+
+ return (SilcClientEntry)id_cache->context;
+}
+
/* Finds channel entry from ID cache by channel name. */
SilcChannelEntry silc_idlist_get_channel(SilcClient client,
client entry. This entry also includes the private message keys if
they are used. */
typedef struct SilcClientEntryStruct {
- char *nickname;
- char *server;
+ char *nickname; /* nickname[@server] */
+ char *username; /* username[@host] */
+ char *server; /* SILC server name */
unsigned int num;
SilcClientID *id;
typedef SilcClientEntryObject *SilcClientEntry;
+/* Client and its mode on a channel */
+typedef struct {
+ SilcClientEntry client;
+ unsigned int mode;
+} SilcChannelUsers;
+
/* Channel entry context. This is allocate for every channel client has
joined to. This includes for example the channel specific keys */
/* XXX channel_key is the server generated key. Later this context must
unsigned int mode;
int on_channel;
- SilcClientEntry *clients;
+ SilcChannelUsers *clients;
unsigned int clients_count;
/* Channel keys */
char *nickname,
char *server,
unsigned int num);
+SilcClientEntry silc_idlist_get_client_by_id(SilcClient client,
+ SilcClientConnection conn,
+ SilcClientID *client_id,
+ int query);
SilcChannelEntry silc_idlist_get_channel(SilcClient client,
SilcClientConnection conn,
char *channel);
void (*private_message)(SilcClient client, SilcClientConnection conn,
char *sender, char *msg);
void (*notify)(SilcClient client, SilcClientConnection conn,
- SilcNotifyPayload notify_payload);
+ SilcNotifyType type, ...);
void (*command)(SilcClient client, SilcClientConnection conn,
SilcClientCommandContext cmd_context, int success,
SilcCommand command);
void (*command_reply)(SilcClient client, SilcClientConnection conn,
SilcCommandPayload cmd_payload, int success,
- SilcCommandStatus status, SilcCommand command, ...);
+ SilcCommand command, SilcCommandStatus status, ...);
void (*connect)(SilcClient client, SilcClientConnection conn, int success);
void (*disconnect)(SilcClient client, SilcClientConnection conn);
int (*get_auth_method)(SilcClient client, SilcClientConnection conn,
SilcSKEPKType pk_type);
unsigned char *(*ask_passphrase)(SilcClient client,
SilcClientConnection conn);
+ void (*failure)(SilcClient client, SilcClientConnection conn,
+ SilcProtocol protocol, void *failure);
} SilcClientOperations;
/*
sender received in the packet.
- void (*notify)(SilcClient client, SilcClientConnection conn,
- SilcNotifyPayload notify_payload);
+ void (*notify)(SilcClient client, SilcClientConnection conn, ...);
- Notify message to the client. The `notify_payload' is the Notify
- Payload received from server. Client library may parse it to cache
- some data received from the payload but it is the application's
- responsiblity to retrieve the message and arguments from the payload.
- The message in the payload sent by server is implementation specific
- thus it is recommended that application will generate its own message.
+ Notify message to the client. The notify arguments are sent in the
+ same order as servers sends them. The arguments are same as received
+ from the server except for ID's. If ID is received application receives
+ the corresponding entry to the ID. For example, if Client ID is received
+ application receives SilcClientEntry. Also, if the notify type is
+ for channel the channel entry is sent to application (even if server
+ does not send it because client library gets the channel entry from
+ the Channel ID in the packet's header).
void (*command)(SilcClient client, SilcClientConnection conn,
Ask (interact, that is) a passphrase from user. Returns the passphrase
or NULL on error.
+
+ void (*failure)(SilcClient client, SilcClientConnection conn,
+ SilcProtocol protocol, void *failure);
+
+ Notifies application that failure packet was received. This is called
+ if there is some protocol active in the client. The `protocol' is the
+ protocol context. The `failure' is opaque pointer to the failure
+ indication. Note, that the `failure' is protocol dependant and application
+ must explicitly cast it to correct type. Usually `failure' is 32 bit
+ failure type (see protocol specs for all protocol failure types).
+
*/
#endif
silc_hmac_set_key(conn->hmac, keymat->hmac_key, keymat->hmac_key_len);
}
+/* XXX TODO */
+
+SilcSKEStatus silc_ske_check_version(SilcSKE ske, unsigned char *version,
+ unsigned int len)
+{
+ return SILC_SKE_STATUS_OK;
+}
+
/* Performs key exchange protocol. This is used for both initiator
and responder key exchange. This may be called recursively. */
protocol->state = SILC_PROTOCOL_STATE_END;
}
break;
+
case SILC_PROTOCOL_STATE_END:
{
/*
silc_protocol_free(protocol);
}
break;
+
case SILC_PROTOCOL_STATE_ERROR:
+ /*
+ * Error during protocol
+ */
+ /* Send abort notification */
+ silc_ske_abort(ctx->ske, ctx->ske->status,
+ silc_client_protocol_ke_send_packet,
+ context);
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
+ break;
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * Received failure from remote.
+ */
+
/* On error the final callback is always called. */
if (protocol->final_callback)
protocol->execute_final(client->timeout_queue, 0, protocol, fd);
case SILC_PROTOCOL_STATE_ERROR:
{
/*
- * Error
+ * Error. Send notify to remote.
*/
+ unsigned char error[4];
+
+ SILC_PUT32_MSB(SILC_CONN_AUTH_FAILED, error);
/* Error in protocol. Send FAILURE packet. Although I don't think
this could ever happen on client side. */
silc_client_packet_send(client, ctx->sock, SILC_PACKET_FAILURE,
- NULL, 0, NULL, NULL, NULL, 0, TRUE);
+ NULL, 0, NULL, NULL, error, 4, TRUE);
/* On error the final callback is always called. */
if (protocol->final_callback)
else
silc_protocol_free(protocol);
}
+
+ case SILC_PROTOCOL_STATE_FAILURE:
+ /*
+ * Received failure from remote.
+ */
+
+ /* On error the final callback is always called. */
+ if (protocol->final_callback)
+ protocol->execute_final(client->timeout_queue, 0, protocol, fd);
+ else
+ silc_protocol_free(protocol);
break;
+
case SILC_PROTOCOL_STATE_UNKNOWN:
break;
}
INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
-I../silcsim -I../.. -I../silcutil -I../../includes \
- -I../silcmath/gmp
+ -I../silcmath/gmp -I../trq
GNU General Public License for more details.
*/
-/*
- * $Id$
- * $Log$
- * Revision 1.6 2000/07/26 07:03:20 priikone
- * Use ID check as well in silc_idcache_add.
- *
- * Revision 1.5 2000/07/18 06:51:48 priikone
- * Use length of data found from cache instead of length of searched
- * data in comparison.
- *
- * Revision 1.4 2000/07/17 11:46:36 priikone
- * Added debug logging
- *
- * Revision 1.3 2000/07/12 05:54:01 priikone
- * Major rewrite of whole ID Cache system.
- *
- * Revision 1.2 2000/07/05 06:06:35 priikone
- * Global cosmetic change.
- *
- * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
- * Imported from internal CVS/Added Log headers.
- *
- *
- */
+/* $Id$ */
#include "silcincludes.h"
#include "idcache.h"
typedef struct SilcChannelKeyPayloadStruct *SilcChannelKeyPayload;
/* Channel modes */
-#define SILC_CHANNEL_MODE_NONE 0x0000
-#define SILC_CHANNEL_MODE_PRIVATE 0x0001 /* private channel */
-#define SILC_CHANNEL_MODE_SECRET 0x0002 /* secret channel */
-#define SILC_CHANNEL_MODE_PRIVKEY 0x0004 /* channel has private key */
-#define SILC_CHANNEL_MODE_INVITE 0x0008 /* invite only channel */
+#define SILC_CHANNEL_MODE_NONE 0x0000
+#define SILC_CHANNEL_MODE_PRIVATE 0x0001 /* private channel */
+#define SILC_CHANNEL_MODE_SECRET 0x0002 /* secret channel */
+#define SILC_CHANNEL_MODE_PRIVKEY 0x0004 /* channel has private key */
+#define SILC_CHANNEL_MODE_INVITE 0x0008 /* invite only channel */
+#define SILC_CHANNEL_MODE_TOPIC 0x0010 /* topic setting by operator */
+#define SILC_CHANNEL_MODE_ULIMIT 0x0020 /* user limit set */
+#define SILC_CHANNEL_MODE_PASSPHRASE 0x0040 /* passphrase set */
+#define SILC_CHANNEL_MODE_BAN 0x0080 /* ban list set */
+#define SILC_CHANNEL_MODE_INVITE_LIST 0x0100 /* invite list set */
+#define SILC_CHANNEL_MODE_CIPHER 0x0200 /* sets cipher of channel */
/* User modes on channel */
-#define SILC_CHANNEL_UMODE_NONE 0x0000
-#define SILC_CHANNEL_UMODE_CHANFO 0x0001 /* channel founder */
-#define SILC_CHANNEL_UMODE_CHANOP 0x0002 /* channel operator */
+#define SILC_CHANNEL_UMODE_NONE 0x0000 /* Normal user */
+#define SILC_CHANNEL_UMODE_CHANFO 0x0001 /* channel founder */
+#define SILC_CHANNEL_UMODE_CHANOP 0x0002 /* channel operator */
/* Prototypes */
SilcChannelPayload silc_channel_payload_parse(SilcBuffer buffer);
return buffer;
}
+/* Same as above but with va_list. */
+
+SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
+ unsigned short ident,
+ unsigned int argc, va_list ap)
+{
+ unsigned char **argv;
+ unsigned int *argv_lens = NULL, *argv_types = NULL;
+ unsigned char *x;
+ unsigned int x_len;
+ unsigned int x_type;
+ SilcBuffer buffer;
+ int i;
+
+ argv = silc_calloc(argc, sizeof(unsigned char *));
+ argv_lens = silc_calloc(argc, sizeof(unsigned int));
+ argv_types = silc_calloc(argc, sizeof(unsigned int));
+
+ for (i = 0; i < argc; i++) {
+ x_type = va_arg(ap, unsigned int);
+ x = va_arg(ap, unsigned char *);
+ x_len = va_arg(ap, unsigned int);
+
+ argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
+ memcpy(argv[i], x, x_len);
+ argv_lens[i] = x_len;
+ argv_types[i] = x_type;
+ }
+
+ buffer = silc_command_payload_encode(cmd, argc, argv,
+ argv_lens, argv_types, ident);
+
+ for (i = 0; i < argc; i++)
+ silc_free(argv[i]);
+ silc_free(argv);
+ silc_free(argv_lens);
+ silc_free(argv_types);
+
+ return buffer;
+}
+
/* Same as above except that this is used to encode strictly command
reply packets. The command status message to be returned is sent as
extra argument to this function. The `argc' must not count `status'
/* Command flags. These set how the commands behave on different
situations. These can be OR'ed together to set multiple flags. */
typedef enum {
- SILC_CF_NONE = 0,
+ SILC_CF_NONE = 0,
/* Command may only be used once per (about) 2 seconds */
- SILC_CF_LAG = (1L << 1),
+ SILC_CF_LAG = (1L << 1),
/* Command is available for registered connections (connections
whose ID has been created. */
- SILC_CF_REG = (1L << 2),
+ SILC_CF_REG = (1L << 2),
/* Command is available only for server operators */
- SILC_CF_OPER = (1L << 3),
+ SILC_CF_OPER = (1L << 3),
/* Command is available only for SILC (router) operators. If this
is set SILC_CF_OPER is not necessary to be set. */
- SILC_CF_SILC_OPER = (1L << 4),
+ SILC_CF_SILC_OPER = (1L << 4),
} SilcCommandFlag;
#define SILC_COMMAND_MOTD 15
#define SILC_COMMAND_UMODE 16
#define SILC_COMMAND_CMODE 17
-#define SILC_COMMAND_KICK 18
-#define SILC_COMMAND_RESTART 19
-#define SILC_COMMAND_CLOSE 20
-#define SILC_COMMAND_DIE 21
-#define SILC_COMMAND_SILCOPER 22
-#define SILC_COMMAND_LEAVE 23
-#define SILC_COMMAND_NAMES 24
+#define SILC_COMMAND_CUMODE 18
+#define SILC_COMMAND_KICK 19
+#define SILC_COMMAND_RESTART 20
+#define SILC_COMMAND_CLOSE 21
+#define SILC_COMMAND_DIE 22
+#define SILC_COMMAND_SILCOPER 23
+#define SILC_COMMAND_LEAVE 24
+#define SILC_COMMAND_NAMES 25
/* Reserved */
#define SILC_COMMAND_RESERVED 255
#define SILC_STATUS_ERR_NO_SUCH_CHANNEL_ID 23
#define SILC_STATUS_ERR_NICKNAME_IN_USE 24
#define SILC_STATUS_ERR_NOT_ON_CHANNEL 25
-#define SILC_STATUS_ERR_USER_ON_CHANNEL 26
-#define SILC_STATUS_ERR_NOT_REGISTERED 27
-#define SILC_STATUS_ERR_NOT_ENOUGH_PARAMS 28
-#define SILC_STATUS_ERR_TOO_MANY_PARAMS 29
-#define SILC_STATUS_ERR_PERM_DENIED 30
-#define SILC_STATUS_ERR_BANNED_FROM_SERVER 31
-#define SILC_STATUS_ERR_BAD_PASSWORD 32
-#define SILC_STATUS_ERR_CHANNEL_IS_FULL 33
-#define SILC_STATUS_ERR_NOT_INVITED 34
-#define SILC_STATUS_ERR_BANNED_FROM_CHANNEL 35
-#define SILC_STATUS_ERR_UNKNOWN_MODE 36
-#define SILC_STATUS_ERR_NOT_YOU 37
-#define SILC_STATUS_ERR_NO_CHANNEL_PRIV 38
-#define SILC_STATUS_ERR_NO_SERVER_PRIV 39
-#define SILC_STATUS_ERR_NO_ROUTER_PRIV 40
-#define SILC_STATUS_ERR_BAD_NICKNAME 41
-#define SILC_STATUS_ERR_BAD_CHANNEL 42
-#define SILC_STATUS_ERR_AUTH_FAILED 43
+#define SILC_STATUS_ERR_USER_NOT_ON_CHANNEL 26
+#define SILC_STATUS_ERR_USER_ON_CHANNEL 27
+#define SILC_STATUS_ERR_NOT_REGISTERED 28
+#define SILC_STATUS_ERR_NOT_ENOUGH_PARAMS 29
+#define SILC_STATUS_ERR_TOO_MANY_PARAMS 30
+#define SILC_STATUS_ERR_PERM_DENIED 31
+#define SILC_STATUS_ERR_BANNED_FROM_SERVER 32
+#define SILC_STATUS_ERR_BAD_PASSWORD 33
+#define SILC_STATUS_ERR_CHANNEL_IS_FULL 34
+#define SILC_STATUS_ERR_NOT_INVITED 35
+#define SILC_STATUS_ERR_BANNED_FROM_CHANNEL 36
+#define SILC_STATUS_ERR_UNKNOWN_MODE 37
+#define SILC_STATUS_ERR_NOT_YOU 38
+#define SILC_STATUS_ERR_NO_CHANNEL_PRIV 39
+#define SILC_STATUS_ERR_NO_SERVER_PRIV 40
+#define SILC_STATUS_ERR_NO_ROUTER_PRIV 41
+#define SILC_STATUS_ERR_BAD_NICKNAME 42
+#define SILC_STATUS_ERR_BAD_CHANNEL 43
+#define SILC_STATUS_ERR_AUTH_FAILED 44
/* Prototypes */
SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer);
SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
unsigned short ident,
unsigned int argc, ...);
+SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
+ unsigned short ident,
+ unsigned int argc, va_list ap);
SilcBuffer
silc_command_reply_payload_encode_va(SilcCommand cmd,
SilcCommandStatus status,
struct SilcNotifyPayloadStruct {
SilcNotifyType type;
unsigned int argc;
- unsigned char *message;
SilcArgumentPayload args;
};
if (len > buffer->len)
goto err;
- silc_buffer_pull(buffer, 5);
- silc_buffer_unformat(buffer,
- SILC_STR_UI_XNSTRING_ALLOC(&new->message, len),
- SILC_STR_END);
-
if (new->argc) {
- silc_buffer_pull(buffer, len);
+ silc_buffer_pull(buffer, 5);
new->args = silc_argument_payload_parse(buffer, new->argc);
- silc_buffer_push(buffer, len);
+ silc_buffer_push(buffer, 5);
}
- silc_buffer_push(buffer, 5);
-
return new;
err:
argument payloads will be associated to the notify payload. Variable
arguments must be {usigned char *, unsigned int (len)}. */
-SilcBuffer silc_notify_payload_encode(SilcNotifyType type, char *message,
- unsigned int argc, va_list ap)
+SilcBuffer silc_notify_payload_encode(SilcNotifyType type, unsigned int argc,
+ va_list ap)
{
SilcBuffer buffer;
SilcBuffer args = NULL;
silc_free(argv_lens);
silc_free(argv_types);
}
-
- i = strlen(message);
- len += 5 + i;
+
+ len += 5;
buffer = silc_buffer_alloc(len);
silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
-
silc_buffer_format(buffer,
SILC_STR_UI_SHORT(type),
- SILC_STR_UI_SHORT(i),
+ SILC_STR_UI_SHORT(len),
SILC_STR_UI_CHAR(argc),
- SILC_STR_UI_XNSTRING(message, i),
SILC_STR_END);
if (argc) {
- silc_buffer_pull(buffer, 5 + i);
+ silc_buffer_pull(buffer, 5);
silc_buffer_format(buffer,
SILC_STR_UI_XNSTRING(args->data, args->len),
SILC_STR_END);
- silc_buffer_push(buffer, 5 + i);
+ silc_buffer_push(buffer, 5);
silc_buffer_free(args);
}
{
if (payload) {
silc_argument_payload_free(payload->args);
- silc_free(payload->message);
silc_free(payload);
}
}
return payload->argc;
}
-/* Return notify message */
-
-unsigned char *silc_notify_get_message(SilcNotifyPayload payload)
-{
- return payload->message;
-}
-
/* Return argument payload */
SilcArgumentPayload silc_notify_get_args(SilcNotifyPayload payload)
#define SILC_NOTIFY_TYPE_SIGNOFF 4 /* "signoff" */
#define SILC_NOTIFY_TYPE_TOPIC_SET 5 /* "topic has been changed" */
#define SILC_NOTIFY_TYPE_NICK_CHANGE 6 /* "has changed nickname" */
+#define SILC_NOTIFY_TYPE_CMODE_CHANGE 7 /* "has changed channel mode" */
+#define SILC_NOTIFY_TYPE_CUMODE_CHANGE 8 /* "has change mode" */
+#define SILC_NOTIFY_TYPE_MOTD 9 /* message of the day */
/* Prototypes */
SilcNotifyPayload silc_notify_payload_parse(SilcBuffer buffer);
-SilcBuffer silc_notify_payload_encode(SilcNotifyType type, char *message,
- unsigned int argc, va_list ap);
+SilcBuffer silc_notify_payload_encode(SilcNotifyType type, unsigned int argc,
+ va_list ap);
void silc_notify_payload_free(SilcNotifyPayload payload);
SilcNotifyType silc_notify_get_type(SilcNotifyPayload payload);
unsigned int silc_notify_get_arg_num(SilcNotifyPayload payload);
-unsigned char *silc_notify_get_message(SilcNotifyPayload payload);
SilcArgumentPayload silc_notify_get_args(SilcNotifyPayload payload);
#endif
SilcPacketParserContext *parse_ctx;
int packetlen, paddedlen, count, mac_len = 0;
+ /* We need at least 2 bytes of data to be able to start processing
+ the packet. */
+ if (sock->inbuf->len < 2)
+ return;
+
if (hmac)
mac_len = hmac->hash->hash->hash_len;
if (packetlen < SILC_PACKET_MIN_LEN) {
SILC_LOG_DEBUG(("Received invalid packet, dropped"));
- continue;
+ return;
}
if (sock->inbuf->len < paddedlen + mac_len) {
return ctx->type;
}
+
+/* Duplicates packet context. Duplicates the entire context and its
+ contents. */
+
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx)
+{
+ SilcPacketContext *new;
+
+ new = silc_calloc(1, sizeof(*new));
+ new->buffer = silc_buffer_copy(ctx->buffer);
+ new->type = ctx->type;
+ new->flags = ctx->flags;
+
+ new->src_id = silc_calloc(ctx->src_id_len, sizeof(*new->src_id));
+ memcpy(new->src_id, ctx->src_id, ctx->src_id_len);
+ new->src_id_len = ctx->src_id_len;
+ new->src_id_type = ctx->src_id_type;
+
+ new->dst_id = silc_calloc(ctx->dst_id_len, sizeof(*new->dst_id));
+ memcpy(new->dst_id, ctx->dst_id, ctx->dst_id_len);
+ new->dst_id_len = ctx->dst_id_len;
+ new->dst_id_type = ctx->dst_id_type;
+
+ new->truelen = ctx->truelen;
+ new->padlen = ctx->padlen;
+
+ new->rng = ctx->rng;
+ new->context = ctx->context;
+ new->sock = ctx->sock;
+
+ return new;
+}
+
+
/* For padding generation */
SilcRng rng;
+
+ /* Back pointers */
+ void *context;
+ SilcSocketConnection sock;
} SilcPacketContext;
/*
void *context);
SilcPacketType silc_packet_parse(SilcPacketContext *ctx);
SilcPacketType silc_packet_parse_special(SilcPacketContext *ctx);
+SilcPacketContext *silc_packet_context_dup(SilcPacketContext *ctx);
#endif
return NULL;
}
+/* Return the ID directly from the raw payload data. */
+
+void *silc_id_payload_parse_id(unsigned char *data, unsigned int len)
+{
+ SilcBuffer buffer;
+ SilcIdType type;
+ unsigned short idlen;
+ unsigned char *id;
+
+ buffer = silc_buffer_alloc(len);
+ silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
+ silc_buffer_put(buffer, data, len);
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_SHORT(&type),
+ SILC_STR_UI_SHORT(&idlen),
+ SILC_STR_END);
+
+ silc_buffer_pull(buffer, 4);
+
+ if (idlen > buffer->len)
+ goto err;
+
+ silc_buffer_unformat(buffer,
+ SILC_STR_UI_XNSTRING_ALLOC(&id, idlen),
+ SILC_STR_END);
+
+ silc_buffer_free(buffer);
+
+ return silc_id_str2id(id, type);
+
+ err:
+ silc_buffer_free(buffer);
+ return NULL;
+}
+
/* Encodes ID Payload */
-SilcBuffer silc_id_payload_encode(void *id, unsigned short len,
- SilcIdType type)
+SilcBuffer silc_id_payload_encode(void *id, SilcIdType type)
{
SilcBuffer buffer;
unsigned char *id_data;
+ unsigned int len;
SILC_LOG_DEBUG(("Parsing ID payload"));
id_data = silc_id_id2str(id, type);
+ len = silc_id_get_len(type);
buffer = silc_buffer_alloc(4 + len);
silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
return silc_id_str2id(payload->id, payload->type);
}
+/* Get raw ID data. Data is duplicated. */
+
+unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
+{
+ unsigned char *ret = silc_calloc(payload->len, sizeof(*ret));
+ memcpy(ret, payload->id, payload->len);
+ return ret;
+}
+
+/* Get length of ID */
+
+unsigned int silc_id_payload_get_len(SilcIDPayload payload)
+{
+ return payload->len;
+}
+
/******************************************************************************
Argument Payload
/* Prototypes */
SilcIDPayload silc_id_payload_parse(SilcBuffer buffer);
-SilcBuffer silc_id_payload_encode(void *id, unsigned short len,
- SilcIdType type);
SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer,
unsigned int argc);
SilcIDPayload silc_id_payload_parse_data(unsigned char *data,
unsigned int len);
+void *silc_id_payload_parse_id(unsigned char *data, unsigned int len);
+SilcBuffer silc_id_payload_encode(void *id, SilcIdType type);
void silc_id_payload_free(SilcIDPayload payload);
SilcIdType silc_id_payload_get_type(SilcIDPayload payload);
void *silc_id_payload_get_id(SilcIDPayload payload);
+unsigned char *silc_id_payload_get_data(SilcIDPayload payload);
+unsigned int silc_id_payload_get_len(SilcIDPayload payload);
SilcBuffer silc_argument_payload_encode(unsigned int argc,
unsigned char **argv,
unsigned int *argv_lens,
the START state or you break every protocol. */
#define SILC_PROTOCOL_STATE_UNKNOWN 0
#define SILC_PROTOCOL_STATE_START 1
-#define SILC_PROTOCOL_STATE_END 253
-#define SILC_PROTOCOL_STATE_ERROR 254
+#define SILC_PROTOCOL_STATE_END 252
+#define SILC_PROTOCOL_STATE_FAILURE 253 /* Received failure from remote */
+#define SILC_PROTOCOL_STATE_ERROR 254 /* Local error at our end */
/* Connection Authentication protocols' authentication methods */
#define SILC_PROTOCOL_CONN_AUTH_NONE 0
#define SILC_PROTOCOL_CONN_AUTH_PASSWORD 1
#define SILC_PROTOCOL_CONN_AUTH_PUBLIC_KEY 2
+/* XXX These don't belong here really! */
+/* Connection authentication protocol status message */
+#define SILC_CONN_AUTH_OK 0
+#define SILC_CONN_AUTH_FAILED 1
+
/* Type definition for above auth methods */
typedef unsigned char SilcProtocolAuthMeth;
INCLUDES = -I. -I.. -I../silccrypt -I../silccore -I../silcske \
-I../silcsim -I../.. -I../silcutil -I../../includes \
- -I./gmp
+ -I./gmp -I../trq
INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
-I../silccore -I../.. -I../silcutil -I../../includes \
- -I../silcmath/gmp
+ -I../silcmath/gmp -I../trq
INCLUDES = -I. -I.. -I../silccrypt -I../silccore -I../silcutil \
-I../silcsim -I../silcmath -I../.. -I../../includes \
- -I../silcmath/gmp
+ -I../silcmath/gmp -I../trq
/*
* $Id$
* $Log$
+ * Revision 1.6 2000/10/31 19:48:31 priikone
+ * A LOT updates. Cannot separate. :)
+ *
* Revision 1.5 2000/07/19 07:04:37 priikone
* Added version detection support to SKE. Minor bugfixes.
*
err:
silc_ske_payload_start_free(payload);
+ ske->status = status;
return status;
}
err:
silc_free(payload);
+ ske->status = status;
return status;
}
if (payload->sign_data)
silc_free(payload->sign_data);
silc_free(payload);
+ ske->status = status;
return status;
}
SILC_LOG_DEBUG(("Allocating new Key Exchange object"));
ske = silc_calloc(1, sizeof(*ske));
+ ske->status = SILC_SKE_STATUS_OK;
return ske;
}
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
if (status == SILC_SKE_STATUS_OK)
return SILC_SKE_STATUS_ERROR;
+ ske->status = status;
return status;
}
SilcSKESendPacketCb send_packet,
void *context)
{
- SilcSKEStatus status = SILC_SKE_STATUS_OK;
SilcBuffer packet;
SILC_LOG_DEBUG(("Start"));
- packet = silc_buffer_alloc(1);
- packet->len = 0;
+ packet = silc_buffer_alloc(4);
+ silc_buffer_pull_tail(packet, SILC_BUFFER_END(packet));
+ silc_buffer_format(packet,
+ SILC_STR_UI_SHORT(SILC_SKE_STATUS_OK),
+ SILC_STR_END);
if (send_packet)
(*send_packet)(ske, packet, SILC_PACKET_SUCCESS, context);
- return status;
+ silc_buffer_free(packet);
+
+ return SILC_SKE_STATUS_OK;
}
/* Aborts the Key Exchange protocol. This is called if error occurs
payload->cookie_len = SILC_SKE_COOKIE_LEN;
memcpy(payload->cookie, rp->cookie, SILC_SKE_COOKIE_LEN);
- /* XXX Do version check */
+ /* Check version string */
+ silc_ske_check_version(ske, rp->version, rp->version_len);
/* Put our version to our reply */
payload->version = strdup(version);
/* Supported Public Key Types, defined by the protocol */
typedef enum {
- SILC_SKE_PK_TYPE_SILC = 1, /* Mandatory type */
- /* Optional types. These are not implemented currently
- SILC_SKE_PK_TYPE_SSH2 = 2,
- SILC_SKE_PK_TYPE_X509V3 = 3,
+ SILC_SKE_PK_TYPE_SILC = 1, /* Mandatory type */
+ /* Optional types. These are not implemented currently */
+ SILC_SKE_PK_TYPE_SSH2 = 2,
+ SILC_SKE_PK_TYPE_X509V3 = 3,
SILC_SKE_PK_TYPE_OPENPGP = 4,
- SILC_SKE_PK_TYPE_SPKI = 5
- */
+ SILC_SKE_PK_TYPE_SPKI = 5
} SilcSKEPKType;
/* Packet sending callback. Caller of the SKE routines must provide
/* Pointer to the what ever user data. This is set by the caller
and is not touched by the SKE. The caller must also free this one. */
void *user_data;
+
+ /* Current status of SKE */
+ SilcSKEStatus status;
};
/* Prototypes */
unsigned int req_enc_key_len,
unsigned int req_hmac_key_len,
SilcSKEKeyMaterial *key);
+SilcSKEStatus silc_ske_check_version(SilcSKE ske,
+ unsigned char *version,
+ unsigned int version_len);
#endif
/* Status flags returned by all SKE routines */
typedef enum {
/* These are defined by the protocol */
- SILC_SKE_STATUS_OK = 0,
- SILC_SKE_STATUS_ERROR = 1,
- SILC_SKE_STATUS_BAD_PAYLOAD = 2,
- SILC_SKE_STATUS_UNKNOWN_GROUP = 3,
- SILC_SKE_STATUS_UNKNOWN_CIPHER = 4,
- SILC_SKE_STATUS_UNKNOWN_PKCS = 5,
- SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION = 6,
+ SILC_SKE_STATUS_OK = 0,
+ SILC_SKE_STATUS_ERROR = 1,
+ SILC_SKE_STATUS_BAD_PAYLOAD = 2,
+ SILC_SKE_STATUS_UNKNOWN_GROUP = 3,
+ SILC_SKE_STATUS_UNKNOWN_CIPHER = 4,
+ SILC_SKE_STATUS_UNKNOWN_PKCS = 5,
+ SILC_SKE_STATUS_UNKNOWN_HASH_FUNCTION = 6,
SILC_SKE_STATUS_UNSUPPORTED_PUBLIC_KEY = 7,
- SILC_SKE_STATUS_INCORRECT_SIGNATURE = 8,
+ SILC_SKE_STATUS_INCORRECT_SIGNATURE = 8,
+ SILC_SKE_STATUS_BAD_VERSION = 9,
SILC_SKE_STATUS_KEY_EXCHANGE_NOT_ACTIVE,
SILC_SKE_STATUS_BAD_RESERVED_FIELD,
INCLUDES = -I. -I.. -I../silccrypt -I../silcmath -I../silcske \
-I../silcsim -I../.. -I../silccore -I../../includes \
- -I../silcmath/gmp
+ -I../silcmath/gmp -I../trq
/*
* $Id$
* $Log$
+ * Revision 1.2 2000/10/31 19:48:32 priikone
+ * A LOT updates. Cannot separate. :)
+ *
* Revision 1.1 2000/09/13 17:45:15 priikone
* Splitted SILC core library. Core library includes now only
* SILC protocol specific stuff. New utility library includes the
#include "silcincludes.h"
#include "silcbuffer.h"
-static unsigned char *silc_buffer_pull_i(SilcBuffer sb, unsigned int len)
-{
- return silc_buffer_pull(sb, len);
-}
-
-static unsigned char *silc_buffer_push_i(SilcBuffer sb, unsigned int len)
-{
- return silc_buffer_push(sb, len);
-}
-
-static unsigned char *silc_buffer_pull_tail_i(SilcBuffer sb, unsigned int len)
-{
- return silc_buffer_pull_tail(sb, len);
-}
-
-static unsigned char *silc_buffer_push_tail_i(SilcBuffer sb, unsigned int len)
-{
- return silc_buffer_push_tail(sb, len);
-}
-
-static unsigned char *silc_buffer_put_head_i(SilcBuffer sb,
- unsigned char *data,
- unsigned int len)
-{
- return silc_buffer_put_head(sb, data, len);
-}
-
-static unsigned char *silc_buffer_put_i(SilcBuffer sb,
- unsigned char *data,
- unsigned int len)
-{
- return silc_buffer_put(sb, data, len);
-}
+#ifdef SILC_DEBUG /* If we are doing debugging we won't
+ have the optimized inline buffer functions
+ available as optimization is not set
+ to compiler. These normal routines are
+ used in debugging mode. */
-static unsigned char *silc_buffer_put_tail_i(SilcBuffer sb,
- unsigned char *data,
- unsigned int len)
-{
- return silc_buffer_put_tail(sb, data, len);
-}
+/* XXX These are currenly obsolete as SILC is compiled always with -O
+ flag thus inline functions maybe used always. So, fix these. */
/* Allocates a new SilcBuffer and returns a pointer to it. The data
area of the new buffer is set to the real beginning of the buffer.
sb->tail = data;
sb->end = data + sb->truelen;
- /* Set the function pointers */
- sb->pull = silc_buffer_pull_i;
- sb->push = silc_buffer_push_i;
- sb->pull_tail = silc_buffer_pull_tail_i;
- sb->push_tail = silc_buffer_push_tail_i;
- sb->put = silc_buffer_put_i;
- sb->put_head = silc_buffer_put_head_i;
- sb->put_tail = silc_buffer_put_tail_i;
-
return sb;
}
}
}
-#ifdef SILC_DEBUG /* If we are doing debugging we won't
- have the optimized inline buffer functions
- available as optimization is not set
- to compiler. These normal routines are
- used in debugging mode. */
-
-/* XXX These are currenly obsolte as SILC is compiled always with -O
- flag thus inline functions maybe used. So, fix these. */
-
/* Pulls current data area towards end. The length of the currently
valid data area is also decremented. Returns pointer to the data
area before pulling.
unsigned char *data;
unsigned char *tail;
unsigned char *end;
-
- /* Method functions. */
- unsigned char *(*pull)(struct SilcBufferStruct *, unsigned int);
- unsigned char *(*push)(struct SilcBufferStruct *, unsigned int);
- unsigned char *(*pull_tail)(struct SilcBufferStruct *, unsigned int);
- unsigned char *(*push_tail)(struct SilcBufferStruct *, unsigned int);
- unsigned char *(*put)(struct SilcBufferStruct *, unsigned char *,
- unsigned int);
- unsigned char *(*put_head)(struct SilcBufferStruct *, unsigned char *,
- unsigned int);
- unsigned char *(*put_tail)(struct SilcBufferStruct *, unsigned char *,
- unsigned int);
} SilcBufferObject;
typedef SilcBufferObject *SilcBuffer;
* functions.
*/
+extern inline
+SilcBuffer silc_buffer_alloc(unsigned int len)
+{
+ SilcBuffer sb;
+ unsigned char *data;
+
+ /* Allocate new SilcBuffer */
+ sb = silc_calloc(1, sizeof(*sb));
+
+ /* Allocate the actual data area */
+ data = silc_calloc(len, sizeof(*data));
+ memset(data, 0, len);
+
+ /* Set pointers to the new buffer */
+ sb->truelen = len;
+ sb->len = 0;
+ sb->head = data;
+ sb->data = data;
+ sb->tail = data;
+ sb->end = data + sb->truelen;
+
+ return sb;
+}
+
+/* Free's a SilcBuffer */
+
+extern inline
+void silc_buffer_free(SilcBuffer sb)
+{
+ if (sb) {
+ memset(sb->head, 'F', sb->truelen);
+ silc_free(sb->head);
+ silc_free(sb);
+ }
+}
+
/* Pulls current data area towards end. The length of the currently
valid data area is also decremented. Returns pointer to the data
area before pulling.
#endif /* !SILC_DEBUG */
/* Prototypes */
+#ifdef SILC_DEBUG
SilcBuffer silc_buffer_alloc(unsigned int len);
void silc_buffer_free(SilcBuffer sb);
-#ifdef SILC_DEBUG
unsigned char *silc_buffer_pull(SilcBuffer sb, unsigned int len);
unsigned char *silc_buffer_push(SilcBuffer sb, unsigned int len);
unsigned char *silc_buffer_pull_tail(SilcBuffer sb, unsigned int len);
is too short. Must be fixed. There are some other obvious bugs as
well. */
/*
- * $Id$
- * $Log$
- * Revision 1.2 2000/09/29 07:11:27 priikone
- * Explcitly cast some va_arg()s as it requires it nowadays.
- *
- * Revision 1.1 2000/09/13 17:45:16 priikone
- * Splitted SILC core library. Core library includes now only
- * SILC protocol specific stuff. New utility library includes the
- * old stuff from core library that is more generic purpose stuff.
- *
- * Revision 1.2 2000/07/05 06:06:35 priikone
- * Global cosmetic change.
- *
- * Revision 1.1.1.1 2000/06/27 11:36:55 priikone
- * Imported from internal CVS/Added Log headers.
- *
- *
- */
+ * $Id$ */
#include "silcincludes.h"
#define SILC_STR_UI_XNSTRING_ALLOC(x, l) \
SILC_BUFFER_PARAM_UI_XNSTRING_ALLOC, (x), (l)
-/* Marks end of the argument list. This must the at the end of the
+/* Marks end of the argument list. This must be at the end of the
argument list or error will occur. */
#define SILC_STR_END SILC_BUFFER_PARAM_END
#include "silcincludes.h"
/* Set TRUE/FALSE to enable/disable debugging */
-int silc_debug;
+int silc_debug = FALSE;
/* SILC Log name strings. These strings are printed to the log file. */
const SilcLogTypeName silc_log_types[] =
static SilcDebugCb debug_cb = NULL;
static SilcDebugHexdumpCb debug_hexdump_cb = NULL;
-/* Formats arguments to a string and returns it after allocating memory
- for it. It must be remembered to free it later. */
-
-char *silc_log_format(char *fmt, ...)
-{
- va_list args;
- static char buf[8192];
-
- memset(buf, 0, sizeof(buf));
- va_start(args, fmt);
- vsnprintf(buf, sizeof(buf) - 1, fmt, args);
- va_end(args);
-
- return strdup(buf);
-}
-
/* Outputs the log message to what ever log file selected. */
void silc_log_output(const char *filename, unsigned int maxsize,
#define SILC_LOG_INFO(fmt) (silc_log_output(log_info_file, \
log_info_size, \
SILC_LOG_INFO, \
- silc_log_format fmt))
+ silc_format fmt))
#define SILC_LOG_WARNING(fmt) (silc_log_output(log_warning_file, \
log_warning_size, \
SILC_LOG_WARNING, \
- silc_log_format fmt))
+ silc_format fmt))
#define SILC_LOG_ERROR(fmt) (silc_log_output(log_error_file, \
log_error_size, \
SILC_LOG_ERROR, \
- silc_log_format fmt))
+ silc_format fmt))
#define SILC_LOG_FATAL(fmt) (silc_log_output(log_fatal_file, \
log_fatal_size, \
SILC_LOG_FATAL, \
- silc_log_format fmt))
+ silc_format fmt))
/* Debug macro is a bit different from other logging macros and it
is compiled in only if debugging is enabled. */
#define SILC_LOG_DEBUG(fmt) (silc_log_output_debug(__FILE__, \
__FUNCTION__, \
__LINE__, \
- silc_log_format fmt))
+ silc_format fmt))
#define SILC_LOG_HEXDUMP(fmt, data, len) \
(silc_log_output_hexdump(__FILE__, \
__FUNCTION__, \
__LINE__, \
(data), (len), \
- silc_log_format fmt))
+ silc_format fmt))
#else
#define SILC_LOG_DEBUG(fmt)
#define SILC_LOG_HEXDUMP(fmt, data, len)
#endif
/* Prototypes */
-char *silc_log_format(char *fmt, ...);
void silc_log_output_debug(char *file, char *function,
int line, char *string);
void silc_log_output(const char *filename, unsigned int maxsize,
/*
* $Id$
* $Log$
+ * Revision 1.2 2000/10/31 19:48:32 priikone
+ * A LOT updates. Cannot separate. :)
+ *
* Revision 1.1 2000/09/13 17:45:16 priikone
* Splitted SILC core library. Core library includes now only
* SILC protocol specific stuff. New utility library includes the
return -1;
}
- /* Set appropriate option */
+ /* Set appropriate options */
silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
SILC_LOG_DEBUG(("Connection created"));
}
}
- /* Set appropriate option */
+ /* Set appropriate options */
silc_net_set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1);
+ silc_net_set_socket_opt(sock, SOL_SOCKET, SO_KEEPALIVE, 1);
SILC_LOG_DEBUG(("Connection operation in progress"));
memcpy(*ip, host_ip, strlen(host_ip));
SILC_LOG_DEBUG(("Resolved IP address `%s'", *ip));
}
+
+/* Return name of localhost. */
+
+char *silc_net_localhost()
+{
+ char hostname[256];
+ if (!gethostname(hostname, sizeof(hostname)))
+ return strdup(hostname);
+ return NULL;
+}
int silc_net_set_socket_opt(int sock, int level, int option, int on);
int silc_net_is_ip(const char *addr);
void silc_net_check_host_by_sock(int sock, char **hostname, char **ip);
+char *silc_net_localhost();
#endif
*parsed_num = argc;
}
+
+/* Formats arguments to a string and returns it after allocating memory
+ for it. It must be remembered to free it later. */
+
+char *silc_format(char *fmt, ...)
+{
+ va_list args;
+ static char buf[8192];
+
+ memset(buf, 0, sizeof(buf));
+ va_start(args, fmt);
+ vsnprintf(buf, sizeof(buf) - 1, fmt, args);
+ va_end(args);
+
+ return strdup(buf);
+}
unsigned int **parsed_types,
unsigned int *parsed_num,
unsigned int max_args);
+char *silc_format(char *fmt, ...);
#endif
echo "Cleaning entire SILC source tree..."
echo "All errors and warnings may be safely ignored."
-make distclean
+make clean -k
+make distclean -k
rm -f includes/stamp-*
rm -f includes/silcconfig.*
rm -f includes/version_internal.h
rm -f lib/silcsim/Makefile.in
rm -f lib/silcsim/modules/Makefile.in
rm -f lib/silcske/Makefile.in
+rm -f lib/trq/Makefile
rm -rf lib/silcmath/gmp/.deps
rm -f silcd/Makefile.in silcd/log* silcd/*.log
rm -f silc/Makefile.in silc/log* silc/*.log
rm -f aclocal.m4
+rm -f config.status
rm -f configure
echo "Done."