updates.
[silc.git] / TODO
1 TODO for 1.2 And Beyond
2 =======================
3
4 NOTE: Any item that doesn't have (***DONE) in it, isn't done yet.  The
5 (***TESTING NEEDED) means that the item has been done but not yet properly
6 tested.
7
8 NOTE: A TODO entry does not mean that it is ever going to be done.  Some
9 of the entries may be just ideas, good, bad or ugly.  If you want to work
10 on some of the TODO entries simply let us know about it by dropping a note
11 to silc-devel mailing list or appear on 'silc' channel on SILCNet.
12
13
14 General
15 =======
16
17  o Create apps/tutorial containing various Toolkit API tutorials.
18
19  o The Toolkit split.  The Toolkit is to be splitted in parts.  How many
20    parts and what the parts are isn't decided yet.  Each part is a separate
21    software package.  Current thinking is of the following:
22
23    SILC Toolkit                 SILC protocol, client and server library
24    SILC Runtime Toolkit         runtime library
25    SILC Crypto Toolkit          crypto, asn1, math, skr, pgp, etc.
26
27    The rationale for this is of course that other than SILC projects
28    might like to use the various libraries SILC Toolkit provides, but
29    naturally they don't want the bloat of SILC protocol related stuff.
30
31    The Runtime library in SILC Toolkit is a general purpose runtime library,
32    like Glib and APR are.  The runtime library is to be developed further
33    to provide alternative to Glib and APR.
34
35    The Crypto library in SILC Toolkit is a general purpose crypto library
36    providing pretty nice APIs compared to many other crypto libraries,
37    especially OpenSSL.  The Crypto library is to be developed further
38    to include support for OpenPGP, X.509 and SSH2.
39
40
41 lib/silccore
42 ============
43
44  o SILC_PACKET_FLAG_ACK support.  Implement ACK packet and packet payload
45    to silcpacket.c.
46
47  o All payload encoding routines should take SilcStack as argument.
48
49  o Remove SilcCommandCb from silccommand.h.
50
51  o All payload test routines into lib/silccore/tests/.
52
53
54 lib/silcclient, The Client Library
55 ==================================
56
57  o Giving WHOIS for nick that doesn't exist should remove any same
58    named entries from the client cache.
59
60  o peer-to-peer private messages
61
62  o Private message key request notification to application.  See XXX in
63    client_prvmsg.c.
64
65  o in JOIN notify handle resolving that timedout.  Currently the user is
66    never joined the channel if this happens.  What to do if message is
67    received from user that hasn't been resolved/joined?
68
69  o Message ACKing support.
70
71  o in /cmode and /cumode with +r, maybe the public key and private key
72    could be just some "string", which would then match to "string.pub" and
73    "string.prv".
74
75  o If the SILC Events (see below) are implemented, perhaps client library
76    should provide events so that application developer has a choice of
77    developing the SILC app with callbacks or with events.
78
79
80 Runtime library, lib/silcutil/
81 ==============================
82
83  o Fix universal time decoding (doesn't accept all formats) in silctime.c.
84
85  o Add functions to manipulate environment variables.
86
87    SilcBool silc_setenv(const char *variable, const char *value);
88    const char *silc_getenv(const char *variable);
89    SilcBool silc_clearenv(const char *variable);
90
91  o Add functions to loading shared/dynamic object symbols (replaces the
92    SIM library (lib/silcsim) and introduces generic library).  Add this
93    to lib/silcutil/silcdll.[ch].
94
95    SilcDll silc_dll_load(const char *object_path, SilcDllFlags flags);
96    void silc_dll_close(SilcDll dll);
97    void *silc_dll_getsym(SilcDll dll, const char *symbol);
98    const char *silc_dll_error(SilcDll dll);
99
100  o Add directory opening/traversing functions
101
102  o silc_getopt routines
103
104  o silc_hash_table_replace -> silc_hash_table_set.  Retain support for
105    silc_hash_table_replace as macro.
106
107  o The SILC Event signals.  Asynchronous events that can be created,
108    connected to and signalled.  Either own event routines or glued into
109    SilcSchedule:
110
111    SilcTask silc_schedule_task_add_event(SilcSchedule schedule,
112                                          const char *event, ...);
113    SilcBool silc_schedule_event_connect(SilcSchedule schedule,
114                                         const char *event,
115                                         SilcTaskCallback event_callback,
116                                         void *context);
117    SilcBool silc_schedule_event_signal(SilcSchedule schedule,
118                                        const char *event, ...);
119
120    Example:
121      silc_schedule_task_add_event(schedule, "connected",
122                                   SILC_PARAM_UI32_INT,
123                                   SILC_PARAM_BUFFER,
124                                   SILC_PARAM_END);
125      silc_schedule_event_connect(schedule, "connected", connected_cb, ctx);
126      silc_schedule_event_signal(schedule, "connected", integer, buf,
127                                  SILC_PARAM_END);
128      SILC_TASK_CALLBACK(connected_cb)
129      {
130        FooCtx ctx = context;
131        va_list args;
132        SilcUInt32 integer;
133        SilcBuffer buf;
134
135        va_start(args, context);
136        integer = va_arg(args, SilcUInt32);
137        buf = va_arg(args, SilcBuffer);
138        va_end(args);
139        ...
140      }
141
142    Problems: Events would be SilcSchedule specific, and would not work on
143    multi-thread/multi-scheduler system.  The events should be copyable
144    between schedulers.  Another problem is the signal delivery.  Do we
145    deliver them synchronously possibly from any thread to any other thread
146    or do we deliver them through the target schedulers.  If we use the
147    schedulers then signalling would be asynchronous (data must be
148    duplicated and later freed) which is not very nice.
149
150  o If the event signals are added, the SILC_PARAM_* stuff needs to be
151    moved from silcbuffmt.h to silctypes.h or something similar.
152
153  o In case the SILC Events are done we shall create a new concept of
154    parent and child SilcSchedule's.  When new SilcSchedule is created a
155    parent can be associated to it.  This association could be done either
156    directly by the parent or by any other children.  This way the signals
157    would in effect be global and would reach all children schedulers.
158
159    This relationship would be associative only.  The schedulers are still
160    independent and run independently from each other.   All schedulers
161    would be linked and could be accessed from any of the schedulers.
162    It should be possible to retrieve the parent and enumate all children
163    from any of the schedulers.
164
165    SilcSchedule silc_schedule_init(int max_tasks, void *app_context,
166                                    SilcSchedule parent);
167    SilcSchedule silc_schedule_get_parent(SilcSchedule schedule);
168
169  o Additional scheduler changes: optimize silc_schedule_wakeup.  Wakeup
170    only if the scheduler is actually waiting something.  If it is
171    delivering tasks wakeup is not needed.
172
173  o Structured log messages to Log API.  Allows machine readable log
174    messages.  Would allow sending of any kind of data in a log message.
175
176  o Base64 to an own API
177
178  o Timer API
179
180  o Add builtin SOCKS and HTTP Proxy support, well the SOCKS at least.
181    SILC currently supports SOCKS4 and SOCKS5 but it needs to be compiled
182    in separately.
183
184  o silc_stringprep to non-allocating version.
185
186  o SilcStack aware SilcHashTable.
187
188  o SilcStack aware SilcDList.
189
190  o Thread pool API.  Add this to lib/silcutil/silcthread.[ch].
191
192    typedef void (*SilcThreadPoolFunc)(SilcSchedule schedule,
193                                       void *context);
194
195    /* Allocate thread pool with at least `min_threads' and at most
196       `max_threads' many threads.  If `stack' is non-NULL all memory
197       is allocated from the `stack'.  If `start_min_threads' is TRUE
198       this will start `min_threads' many threads immediately. */
199    SilcThreadPool silc_thread_pool_alloc(SilcStack stack,
200                                          SilcUInt32 min_threads,
201                                          SilcUInt32 max_threads,
202                                          SilcBool start_min_threads);
203
204    /* Free thread pool.  If `wait_unfinished' is TRUE this will block
205       and waits that all remaining active threads finish before freeing
206       the pool. */
207    void silc_thread_pool_free(SilcThreadPool tp, SilcBool wait_unfinished);
208
209    /* Run `run' function with `run_context' in one of the threads in the
210       thread pool.  Returns FALSE if the thread pool is being freed.  If
211       there are no free threads left in the pool this will queue the
212       the `run' and will call it once a thread becomes free.
213
214       If `completion' is non-NULL it will be called to indicate completion
215       of the `run' function.  If `schedule' is non-NULL the `completion'
216       will be called through the scheduler in the main thread.  If it is
217       NULL the `completion' is called directly from the thread after the
218       `run' has returned. */
219    SilcBool silc_thread_pool_run(SilcThreadPool tp,
220                                  SilcSchedule schedule,
221                                  SilcThreadPoolFunc run,
222                                  void *run_context,
223                                  SilcThreadPoolFunc completion,
224                                  void *completion_context);
225
226    /* Modify the amount of maximum threads of the pool. */
227    void silc_thread_pool_set_max_threads(SilcThreadPool tp,
228                                          SilcUInt32 max_threads);
229
230    /* Returns the amount of maximum size the pool can grow. */
231    SilcUInt32 silc_thread_pool_num_max_threads(SilcThreadPool tp);
232
233    /* Returns the amount of free threads in the pool currently. */
234    SilcUInt32 silc_thread_pool_num_free_threads(SilcThreadPool tp);
235
236    /* Stops all free and started threads.  The minumum amount of threads
237       specified to silc_thread_pool_alloc always remains. */
238    void silc_thread_pool_purge(SilcThreadPool tp);
239
240  o Fast mutex implementation.  Fast rwlock implementation.  Mutex and
241    rwlock implementation using atomic operations.
242
243  o Compression routines are missing.  The protocol supports packet
244    compression thus it must be implemented.  SILC Zip API must be
245    defined.
246
247  o Add new functions to SilcStack API in lib/silcutil/silcstack.[ch].  Add
248    silc_stack_[set|get]_alignment.  It defines the default alignment used
249    when allocating memory from stack.  It can be used to specify special
250    alignments too when needed (such as for hardware devices like crypto
251    accelerators).  Move also the low level silc_stack_malloc and
252    silc_stack_realloc from silcstack_i.h to silcstack.h.  Remove the
253    _ua unaligned memory allocation routines.  Remove unaligned memory
254    allocation possibility.
255
256  (o Generic SilcStatus or SilcResult that includes all possible status and
257     error conditions, including those of SILC protocol.  Though, the SILC
258     protocol related status (currently in silcstatus.h) cannot be in
259     runtime library) maybe
260
261  (o SILC specific socket creation/closing routines to silcnet.h, wrappers
262   to all send(), recv(), sendto() etc.  Bad thing is that we'd have to
263   define all socket options, sockaddrs, etc.) maybe
264
265  (o mmap) maybe
266
267
268 lib/silcutil/symbian/
269 =====================
270
271  o Something needs to be thought to the logging globals as well,
272    like silc_debug etc.  They won't work on EPOC.  Perhaps logging
273    and debugging is to be disabled on EPOC.  The logging currently works
274    by it cannot be controlled, same with debugging.
275
276
277 SFTP Library, lib/silcsftp/
278 ===========================
279
280  o Read prefetch (read-ahead, reading ahead of time).  Maybe if this can
281    be done easily.
282
283
284 SKR Library, lib/silcskr/
285 =========================
286
287  o Add fingerprint as search constraint.
288
289  o Add OpenPGP support.  Adding, removing, fetching PGP keys.  (Keyring
290    support?)
291
292  o Add support for importing public keys from a directory and/or from a
293    file.  Add support for exporting the repository (different formats for
294    different key types?).
295
296  o Change the entire silc_skr_find API.  Remove SilcSKRFind and just simply
297    add the find constraints as variable argument list to silc_skr_find, eg:
298
299   silc_skr_find(skr, schedule, callback, context,
300                 SILC_SKR_FIND_PUBLIC_KEY, public_key,
301                 SILC_SKR_FIND_COUNTRY, "FI",
302                 SILC_SKR_FIND_USAGE, SILC_SKR_USAGE_AUTH,
303                 SILC_SKR_FIND_END);
304
305    NULL argument would be ignored and skipped.
306
307  o Add OR logical rule in addition of the current default AND, eg:
308
309   // Found key(s) MUST have this public key AND this country.
310   silc_skr_find(skr, schedule, callback, context,
311                 SILC_SKR_FIND_RULE_AND,
312                 SILC_SKR_FIND_PUBLIC_KEY, public_key,
313                 SILC_SKR_FIND_COUNTRY, "FI",
314                 SILC_SKR_FIND_END);
315
316   // Found key(s) MUST have this public key OR this key context
317   silc_skr_find(skr, schedule, callback, context,
318                 SILC_SKR_FIND_RULE_OR,
319                 SILC_SKR_FIND_PUBLIC_KEY, public_key,
320                 SILC_SKR_FIND_CONTEXT, key_context,
321                 SILC_SKR_FIND_END);
322
323  o SilcStack to SKR API.
324
325
326 Crypto Library, lib/silccrypt/
327 ==============================
328
329  o SilcStack to APIs.
330
331  o Add fingerprint to SilcSILCPublicKey and retrieval to silcpk.h, and
332    possibly to silcpkcs.h.
333
334    /* Return fingerprint of the `public_key'.  Returns also the algorithm
335       that has been used to make the fingerprint. */
336    const unsigned char *
337    silc_pkcs_get_fingerprint(SilcPublicKey public_key,
338                              const char **hash_algorithm,
339                              SilcUInt32 *fingerprint_len);
340
341  o Change SILC PKCS API to asynchronous, so that accelerators can be used.
342    All PKCS routines should now take callbacks as argument and they should
343    be delivered to SilcPKCSObject and SilcPKCSAlgorithm too.
344
345    /* Signature computation callback */
346    typedef void (*SilcPKCSSignCb)(SilcBool success,
347                                   const unsigned char *signature,
348                                   SilcUInt32 signature_len,
349                                   void *context);
350
351    /* Signature verification callback */
352    typedef void (*SilcPKCSVerifyCb)(SilcBool success, void *context);
353
354    /* Encryption callback */
355    typedef void (*SilcPKCSEncryptCb)(SilcBool success,
356                                      const unsigned char *encrypted,
357                                      SilcUInt32 encrypted_len,
358                                      void *context);
359
360    /* Decryption callback */
361    typedef void (*SilcPKCSDecryptCb)(SilcBool success,
362                                      const unsigned char *decrypted,
363                                      SilcUInt32 decrypted_len,
364                                      void *context);
365
366    Either add new _async functions or add the callbacks to existing API
367    and if the callback is NULL then the API is not async and if provided
368    it may be async.  For example;
369
370    SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
371                            unsigned char *src, SilcUInt32 src_len,
372                            unsigned char *dst, SilcUInt32 dst_size,
373                            SilcUInt32 *dst_len,
374                            SilcBool compute_hash, SilcHash hash,
375                            SilcPKCSSignCb async_sign,
376                            void *async_sign_context);
377
378    (if this is done then there's no reason why the buffers in the
379     callbacks cannot be the ones user gives here) or allow only async:
380
381    SilcBool silc_pkcs_sign(SilcPrivateKey private_key,
382                            unsigned char *src, SilcUInt32 src_len,
383                            SilcBool compute_hash, SilcHash hash,
384                            SilcPKCSSignCb async_sign,
385                            void *async_sign_context);
386
387    or add new:
388
389    SilcBool silc_pkcs_sign_async(SilcPrivateKey private_key,
390                                  unsigned char *src, SilcUInt32 src_len,
391                                  SilcBool compute_hash, SilcHash hash,
392                                  SilcPKCSSignCb async_sign,
393                                  void *async_sign_context);
394
395  o Change PKCS Algorithm API to take SilcPKCSAlgorithm as argument to
396    encrypt, decrypt, sign and verify functions.  We may need to for exmaple
397    check the alg->hash, supported hash functions.  Maybe deliver it also
398    to all other functions in SilcPKCSAlgorithm to be consistent.
399
400  o Add DSS support.  Take implementation from Tom or make it yourself.
401
402  o Implement the defined SilcDH API.  The definition is in
403    lib/silccrypt/silcdh.h.  Make sure it is asynchronous so that it can
404    be accelerated.  Also take into account that it could use elliptic
405    curves.
406
407  o ECDSA and ECDH
408
409  o All cipher, hash, hmac etc. allocation routines should take their name
410    in as const char * not const unsigned char *.
411
412
413 SILC Accelerator Library
414 ========================
415
416  o SILC Accelerator API.  Provides generic way to use different kind of
417    accelerators.  Basically implements SILC PKCS API so that SilcPublicKey
418    and SilcPrivateKey can be used but they call the accelerators.
419
420    Something in the lines of (preliminary):
421
422    /* Register accelerator to system.  Initializes the accelerator. */
423       Varargs are optional accelerator specific init parameteres. */
424    SilcBool silc_acc_register(SilcAccelerator acc, ...);
425
426      silc_acc_register(softacc, "min_threads", 2, "max_threads", 16, NULL);
427
428    /* Unregister accelerator.  Uninitializes the accelerator. */
429    SilcBool silc_acc_unregister(const SilcAccelerator acc);
430
431    /* Return list of the registered accelerators */
432    SilcDList silc_acc_get_supported(void);
433
434    /* Find existing accelerator.  `name' is accelerator's name. */
435    SilcAccelerator silc_acc_find(const char *name);
436
437    /* Return accelerator's name */
438    const char *silc_acc_get_name(SilcAccelerator acc);
439
440    /* Accelerate `public_key'.  Return accelerated public key. */
441    SilcPublicKey silc_acc_public_key(SilcAccelerator acc,
442                                      SilcPublicKey public_key);
443
444    /* Accelerate `private_key'.  Returns accelerated private key. */
445    SilcPrivateKey silc_acc_private_key(SilcAccelerator acc,
446                                        SilcPrivateKey private_key);
447
448    /* Return the underlaying public key */
449    SilcPublicKey silc_acc_get_public_key(SilcAccelerator acc,
450                                          SilcPublicKey public_key);
451
452    /* Return the underlaying private key */
453    SilcPrivateKey silc_acc_get_private_key(SilcAccelerator acc,
454                                            SilcPrivateKey private_key);
455
456    typedef struct SilcAcceleratorObject {
457      const char *name;                  /* Accelerator's name */
458      SilcBool (*init)(va_list va);      /* Initialize accelerator */
459      SilcBool (*uninit)(void);          /* Uninitialize accelerator */
460      const SilcPKCSAlgorithm *pkcs;     /* Accelerated PKCS algorithms */
461      const SilcDHObject *dh;            /* Accelerated Diffie-Hellmans */
462      const SilcCipherObject *cipher;    /* Accelerated ciphers */
463      const SilcHashObject *hash;        /* Accelerated hashes */
464      const SilcHmacObject *hmac;        /* Accelerated HMACs */
465      const SilcRngObject *rng;          /* Accelerated RNG's */
466    } *SilcAccelerator, SilcAcceleratorStruct;
467
468    Allows accelerator to have multiple accelerators (cipher, hash etc)
469    and multiple different algorithms and implementations (SHA-1, SHA-256 etc).
470
471    SilcPublicKey->SilcSILCPublicKey->RsaPublicKey accelerated as:
472    SilcPublicKey->SilcAcceleratorPublicKey->SilcSoftAccPublicKey->
473      SilcPublicKey->SilcSILCPublicKey->RsaPublicKey
474
475    silc_acc_public_key creates SilcPublicKey and SilcAcceleratorPublicKey
476    and acc->pkcs->import_public_key creates SilcSoftAccPublicKey.
477
478  o Implement software accelerator.  It is a thread pool system where the
479    public key and private key operations are executed in threads.
480
481    const struct SilcAcceleratorObject softacc =
482    {
483      "softacc", softacc_init, softacc_uninit,
484      softacc_pkcs, NULL, NULL, NULL, NULL
485    }
486
487    /* Called from silc_acc_private_key */
488    int silc_softacc_import_private_key(void *key, SilcUInt32 key_len,
489                                        void **ret_private_key)
490    {
491      SilcSoftAccPrivateKey prv = silc_calloc(1, sizeof(*prv));
492      prv->pkcs = acc->pkcs;
493      prv->private_key = key;
494      *ret_private_key = prv;
495    }
496
497  (o Symmetric key cryptosystem acceleration?  They are always sycnhronouos
498    even with hardware acceleration so the crypto API shouldn't require
499    changes.) maybe
500
501
502 lib/silcmath
503 ============
504
505  o Import TFM.  Talk to Tom to add the missing functions.  Use TFM in
506    client and client library, but TMA in server, due to the significantly
507    increased memory consumption with TFM, and the rare need for public
508    key operations in server.
509
510    We want TFM's speed but not TFM's memory requirements.  Talk to Tom
511    about making the TFM mp dynamic just as it is in LTM.
512
513  o The SILC MP API function must start returning indication of success
514    and failure of the operation.
515
516  o Do SilcStack support for silc_mp_init, silc_mp_init_size and other
517    any other MP function (including utility ones) that may allocate
518    memory.
519
520  o All utility functions should be made non-allocating ones.
521
522
523 SILC XML Library, lib/silcxml/
524 ==============================
525
526  o SILC XML API (wrapper to expat).  Look at the expat API and simplify
527    it.  The SILC XML API should have at most 8-10 API functions.  It should
528    be possible to create full XML parser with only one function.  And, it
529    should be possible to have a function that is able to parse an entire
530    XML document.  It should also have a parser function to be able to
531    parse a stream of XML data (SilcStream).  It MUST NOT have operations
532    that require multiple function calls to be able to execute that one
533    operation (like creating parser).
534
535
536 lib/silcske/silcske.[ch]
537 ========================
538
539  o Ratelimit to UDP/IP transport for incoming packets.
540
541
542 lib/silcasn1
543 ============
544
545  o Negative integer encoding is missing, add it.
546
547  o SILC_ASN1_CHOICE should perhaps return an index what choice in the
548    choice list was found.  Currently it is left for caller to figure out
549    which choice was found.
550
551  o SILC_ASN1_NULL in decoding should return SilcBool whether or not
552    the NULL was present.  It's important when it's SILC_ASN1_OPTIONAL
553    and we need to know whether it was present or not.
554
555
556 lib/silcpgp
557 ===========
558
559  o OpenPGP certificate support, allowing the use of PGP public keys
560    in SILC.
561
562
563 lib/silcssh
564 ===========
565
566  o SSH2 public key/private key support, allowing the use of SSH2 keys
567    in SILC.  RFC 4716.
568
569
570 lib/silcpkix
571 ============
572
573  o PKIX implementation
574
575
576 apps/silcd
577 ==========
578
579  o Deprecate the old server.  Write interface for the new lib/silcserver
580    server library.  The interface should work on Unix/Linux systems.
581
582  o Consider deprecating also the old config file format and use XML
583    istead.  This should require SILC XML API implementation first.
584
585  o The configuration must support dynamic router and server connections.
586    The silcd must work without specifying any servers or routers to
587    connect to.
588
589  o The configuration must support specifying whether the server is
590    SILC Server or SILC Router.  This should not be deduced from the
591    configuration as it was in < 1.2.
592
593  o The configuration must support specifying the ciphers and hmacs and
594    their order so that user can specify which algorithms take preference.
595
596
597 lib/silcserver
598 ==============
599
600  o Rewrite the entire server.  Deprecate apps/silcd as the main server
601    implementation and create lib/silcserver/.  It is a platform
602    independent server library.  The apps/silcd will merely provide a
603    a simple interface for the library.
604
605  o Write the SILC Server library extensively using SILC FSM.
606
607  o Server library must support multiple networks.  This means that one
608    server must be able to create multiple connections that each reach
609    different SILC network.  This means also that all cache's etc. must
610    be either connection-specific or network-specific.
611
612  o Library must support dynamic router and server connections.  This means
613    that connections are create only when they are needed, like when someone
614    says JOIN foo@foo.bar.com or WHOIS foobar@silcnet.org.
615
616  o Library must support server-to-server connections even though protocol
617    prohibits that.  The responder of the connection should automatically
618    act as a router.  The two servers create an own, isolated, SILC network.
619    To be used specifically with dynamic connections.
620
621  o Library must support multiple threads and must be entirely thread safe.
622
623  o Library must have support for SERVICE command.
624
625  o The server must be able to run behind NAT device.  This means that 
626    Server ID must be based on public IP instead of private IP.
627
628  o The following data must be in per-connection context: client id cache, 
629    server id cache, channel id cache, all statistics must be 
630    per-connection.
631
632  o The following data must be in per-thread context: command context
633    freelist/pool, pending commands, random number generator.
634
635  o Do inccoming packet processing in an own FSM thread in the 
636    server-threads FSM.  Same as in client library.
637
638  o Reference count all Silc*Entry structures.
639
640  Some issues that must be kept in mind from 1.0 and 1.1 silcd's:
641
642  o The SERVER_SIGNOFF notify handing is not optimal, because it'll
643    cause sending of multiple SIGNOFF notify's instead of the one
644    SERVER_SIGNOFF notify that the server received.  This should be
645    optimized so that the only SERVER_SIGNOFF is sent and not
646    SIGNOFF of notify at all (using SIGNOFF takes the idea about
647    SERVER_SIGNOFF away entirely).
648
649  o Another SERVER_SIGNOFF opt/bugfix:  Currently the signoff is
650    sent to a client if it is on same channel as the client that
651    signoffed.  However, the entire SERVER_SIGNOFF list is sent to
652    the client, ie. it may receive clients that was not on the
653    same channel.  This is actually against the specs.  It must be
654    done per channel.  It shouldn't receive the whole list just
655    because one client happened to be on same channel.
656
657  o If client's public key is saved in the server (and doing public key
658    authentication) then the hostname and the username information could
659    be taken from the public key.  Should be a configuration option!
660
661  o Add a timeout to handling incoming JOIN commands.  It should be
662    enforced that JOIN command is executed only once in a second or two
663    seconds.  Now it is possible to accept n incoming JOIN commands
664    and process them without any timeouts.  THis must be employed because
665    each JOIN command will create and distribute the new channel key
666    to everybody on the channel.
667
668  o Related to above.  If multiple JOINs are received in sequence perhaps
669    new key should be created only once, if the JOINs are handeled at the same
670    time.  Now we create multiple keys and never end up using them because
671    many JOINs are processed at the same time in sequence.  Only the last
672    key ends up being used.