znc/znc — pull request #80 by stephank (2011-10-18 18:29:00+00:00)
Title: Capability for machine readable timestamps

This pull request adds a capability `znc.in/server-time`, which when requested will disable regular timestamp formatting for the connection, and instead extend the IRC protocol by sending unix timestamps.

* Clients can format time in any format and any timezone, regardless of ZNC settings.
* There is no ambiguity or loss of precision when determining time of a message passed on by ZNC.
* Clients with and without support can be mixed and matched, even have simultaneous connections, with expected results.

---

The protocol change is simple: when activated, clients must expect an optional time token at the start of each message from the server. The message BNF in the original RFC is extended to look roughly like:

::= ['@' ] [':' ]

Here's the start of a session with a ZNC connected to FreeNode:

CAP REQ znc.in/server-time
CAP END
PASS foobar:foobar
NICK foobar
USER foobar "foobar" "foobar" :foobar
PRIVMSG *status :JumpNetwork FreeNode
:irc.znc.in CAP unknown-nick ACK :znc.in/server-time
:irc.znc.in 001 foobar :- Welcome to ZNC -
@1318958620 :barjavel.freenode.net 001 foobar :Welcome to the freenode Internet Relay Chat Network foobar

There's a matching branch of LimeChat implementing this capability at:
https://github.com/stephank/limechat/tree/server-time

---

For ZNC, I've included the optional timestamps only for buffer lines for now, but it could be extended to all messages ZNC sends to clients. (Don't really have a solid case for that.) ZNC also doesn't use the capability in its own client connections (IRCSock).

Implementation-wise, the interesting changes happen in CBuffer code.

Time formatting needs to be done at the moment buffers are flushed to the client, rather than at the time a line is received by ZNC. CBuffer already had rough formatting capability at flush time with the `bIncNick` flag.

To keep things simple when adding extra formatting parameters, a simple string formatting utility was added, and CBufLine stores a format string interpolated at flush time. For example, a format string would look like:

:barjavel.freenode.net 001 {target} :Welcome to the freenode Internet Relay Chat Network foobar

CBufLine is now responsible for adding the timestamp. To make this work, channel buffering now also uses CBuffer. `GetLine` takes the CClient object for context (see if server-time is activated, access to the CUser otherwise).

Note that the first two commits are for minor build issues I encountered.

---

At the time of writing, the savebuf module compiles but is broken.

Buffer lines store metadata which must be also be serialized and written to the buffer file if we want this to work properly. Technically, this module has always been slightly broken, because it couldn't honor `bIncNick`.

Would like to hear your thoughts on what to do with the savebuf file format.