I've had at least a few rewrite plans before, but they've pretty much
sucked. Now, I think I'm finally enlightened enough and could actually
design a good new irssi.

Rewrites are usually bad idea with large projects, they mostly just get
started and get never finished, or not at least for a long time. But I think
rewrite is pretty much the only solution for irssi now, crash reports that I
get nowadays are rarely usable, I just know that "something" happened
"somewhere" which caused this crash later (heap corruption). I'd guess it's
usually a script.

So, new plan is basically: Write code that doesn't crash. Ever. 

Well, maybe not that strict. Crashing isn't too bad if it's predictable.
Asserts and NULL pointer accesses are fine, heap corruption is not. ie. if
it crashes, the core dump must show exactly the reason why it crashed, so it
can be fixed without guessing.

I'd hope some other people also would write code to this, it would take
quite a long time before I can get anything usable out of it alone. Design
ideas are also welcome, especially (simple) generalized features that make a
whole set of other features unnecessary (eg. /match below).

So, here's some of my thoughts, both from code and feature point of view,
comments welcome:

Code
----

coding style:
 - still C. it's the language I know well and like :)
 - must not crash, ever, no matter what you did
    - asserts and NULL pointer accesses are somewhat acceptable
    - anything else - especially heap corruption - means the
      design is flawed and must be fixed
 - type safety
    - void pointers lose type safety, avoid them
       - callback functions usually want them -> avoid them
    - casts are dangerous, avoid them
 - unions are dangerous, don't access them directly but rather
   through macros/functions which checks that you're accessing
   the correct element (eg. union { int i; char *s; } u;
   u.i = user_input(); .... *s = 0; -> security hole)
 - char* means it's NUL terminated, unsigned char* means it's not.
 - don't modify buffers directly unless you really have to.
   use string and buffer APIs.
 - any part of code where it takes more than a glance to verify
   that there's no buffer overflows, mark it with /* @UNSAFE */
   ie. foo(buffer, sizeof(buffer)) is OK, almost everything else
   is not.
 - don't overdesign
 - minimize the code, make everything simple to use
 - C doesn't set limitations on what you can do. If it seems
   difficult to implement or hard to use, rethink it better.
 - if it requires coder to be careful, it's usually badly 
   designed

memory management:
 - heap allocations aren't exactly fast and it gets fragmented
 - free() is dangerous, avoid it when possible
    - garbage collectors would help, but they don't work well
      with Perl (leaks a lot)
 - use allocate-only memory pools and data stack for temporary
   memory allocations. fast and safe.
 - possibly create a string memory pool which allows
   defragmenting by moving the data (special pstring_t type)

objects:
 - inheritance is annoying with C, probably do it like:
   struct irc_server { struct server server; ... }; to keep type
   safety. A bit annoying to access server struct though.
 - reference counting is needed, especially for Perl interface
 - there aren't many objects, so they could contain extra data
   set by plugins/scripts (especially the perl plugin itself)
     - except for nick object. should it be special case?..

signals:
 - requires better type safety. at the very least change the
   signals to emit a single parameters-structure instead of
   a number of C pointers, and check that the parameters are
   what the signal expects.
 - that could still lead to runtime errors. maybe we should have
   a separate signal_emit() function for each signal? .. would
   generate more code though, but much less chance for runtime
   errors.

perl:
 - keep the perl objects permanently in memory, attach it with
   the extra object data. it's created when object is first used
   in perl, it's destroyed when object itself is destroyed
 - update object's reference counter while perl object's refcount
   is updated. so it's possible to store object permanently to
   perl's memory and access it even when C code has already
   forgotten it -> scripts can't crash irssi

Tags
----

Message levels will be replaced by tags. New tags can be
dynamically registered and their amount is not limited. They're
internally stored in variable width bitmask. Tags may have
parameters.,for example HILIGHT tag could have priority parameter.
Tags may automatically set/unset other tags.

Tags will play a big role in how things will interoperate, mostly
by making signals tagged. For example signal can be marked with
IGNORE, HILIGHT and/or LOG tags.

/MATCH
------

Ignores, hilights, /set activity_*, etc. will be replaced by /MATCH
command. /IGNORE and /HILIGHT may be left as wrappers to /MATCH. It
works in very similiar way to IP packet filters and such. You
describe the events you wish to match against and action what to do
then. Usually the action would be to set a tag for the signal, or
maybe to remove a tag.

Examples:
/match from *!*@*.fi to #channel join part -> +hilight
/match from *[EMAIL PROTECTED] ctcp -> +ignore
/match from *[EMAIL PROTECTED] all -> +ignore +log

Ignore-tag would automatically do -log, so the last example would
still log the user.

The matches should probably be saved in own file which would look
like the above examples without /match. That way it'd be easy to
edit it with text editor, again very much like firewall rules.

/MATCH could possibly be also used like ircII /ON.

Logging
-------

Needs rethinking. Currently we log what gets shown in screen, using
whatever theme happens to be set (well, there's /set log_theme).
That's anyway wrong way to do it. We want to log different things
than what we want in screen. Logs should look the same by default,
no matter what theme you were using.

I'm thinking of creating a seprate /match ruleset against what to
log .. That should be separate from the list shown with /match not
to confuse users.. Needs more thinking.

Anyway, things that should be possible:
 - --> nick!user@host -> you!your@host:
   --> Nick is Real Name (from /whois reply)
   <nick> foo
   <you> bar
   --> nick!user@host2 -> you!your@host:
   --> Nick is Real Name
   <nick> dialup reconnection
 - <nick:#channel> ...
 - .. what else ..

Screen filter
-------------

It should be possible to hide/remove data from window buffers. So
you could have some key to toggle between showing joins, parts,
ignored people, etc.

Command line
------------

Commands will contain information what their parameters are, so irssi
actually knows what should be tab completed. For example
/server add -network <tab> knows that it should start completing
IRC networks.

All completed word positions should be marked, so that if you modify
the line elsewhere, go over the completed word and hit tab, it would
continue the old completion list. Completed words could be marked
with different color or underlining.

Different colorings would allow other things to be done, like spell
checker underlining invalid words, hitting tab over them would try to
fix the word.

The completed text would be marked using some tag .. possibly from
entirely different tagset as described above. The text anyway that
gets executed could be different than what's shown in screen. For
example we could redefine people to use different nicks, tab
completion would show us redefined nick, but what actually gets sent
to server would be the real nick.

There could possibly be also automatic modifications to some
command parameters. For example script creating random
kick/quit/part reason if a command parameter with REASON-tag
is empty.

Settings
--------

Several settings should be channel/server/network specific. Make it
so that all settings actually are, if possible. In code this would
be done like: settings_get_channel(channel, "sync") which would try
first channel specific settings, then server, then network and finally
fallback to globals.

I'm not sure how user would change them. Maybe
/set -channel #foo -network ircnet sync ...

Misc
----

Not being able to write to screen shouldn't block the whole program.
So if ^S was pressed, irssi should continue on the background
until ^Q was pressed, when it would just redraw the screen.

Support uTF-8 using terminal's UTF-8 on/off feature. Support
terminal's "alternate character set" on/off feature to allow drawing
lines and such.

Good internal iconv() support, to allow very simple to use UTF-8
support.

Statusbar? It's actually quite good now, I think. Could be easier to
setup of course.

Internal scripting? The current $vars are quite near scripting
themselves. Maybe we should have some very simple language to use in
themes, statusbars and such.


Reply via email to