@node Architecture @unnumbered Architecture Brief scheme of commands, utilities and files involved is below. @file{F} means files/FIFOs/directories creation and altering. @file{R} means running of external programs. @verbatim cmd/start F tmux.conf R tmux -f tmux.conf R tail -f debug | tai64n R for { cat users/status ; sleep 5 } R cmd/mmc | tai64n F users/status F users/.../{id,email,name,|in,out.rec,|status,last} F chans/.../{id,info,out.rec,|users,last} F file/{|get,|out} R cmd/notify R tmux display-message ... R cmd/newwin R cmd/rd/colourized R cmd/rd < .../out.rec | spc R cmd/wr R for { rlwrap cat > .../in } R fzf **(/) | cmd/newwin R tmux capture-pane | fzf | cmd/dl R cmd/catfile R fzf **(.) | fmt cmd/dl R echo ... > file/get R tar xf < file/out cmd/sb ... > history.rec @end verbatim @url{https://tools.suckless.org/ii/usage/, ii} IRC client's page has many links to similar kind of chat software. There is some long-living program, that deals with the messaging protocol and communicates with other programs through the FIFO files. There are user chats and group chats, both in IRC, XMPP and MM worlds. Each user and channel have corresponding directory having the same name. It contains @file{in} and @file{out} named pipes. Anything you write to @file{in} will be send as a message to corresponding user/channel. Reading from @file{out} will give you incoming messages from that user/channel. That is the basic idea of the backend. All you need is to write the frontend that will give you convenient ability to deal with all that bunch of files. That is the most complicated part of course. I do not like idea of having the single window with consolidation of all chats, like using @command{multitail} on several pipes. I do not like idea of purely CLI utility like @url{https://github.com/agl/xmpp-client, github.com/agl/xmpp-client}, @url{https://en.wikipedia.org/wiki/MICQ, mICQ} or @url{https://www.gnu.org/software/freetalk/, GNU Freetalk}, where you have to carefully be aware of whom you are typing now. I like @command{irssi} and @command{mcabber}, where you have got separate window with per-user/channel output and input. We must have ability to hide/close those windows/tabs/panes, automatically open them if they got incoming events and we must be alerted about those events, at least by bell character. @url{https://github.com/tmux/tmux/wiki, tmux} is a perfect tool for dynamic windows/tabs/panes management. It already has all necessary functions to detect bell/alarms. It have ability to easily create you own keybindings and already have massive amount of convenient hotkeys to quickly navigate among all that windows. It already has history buffer and ability to search in it. And it is likely to be already used by the end user. Messages have to be saved on filesystem. Unlike IRC, MM messages are often multiline and can have additional metadata like unique identifiers and attached files. So each message is a more complicated entity than text string with appended timestamp and sender information. Each time chat window is opened, I want to see tail of the corresponding history. So instead of using FIFO that is @command{tee}-ed to ordinary long-living file, I decided to use append-only @url{https://www.gnu.org/software/recutils/, GNU Recutils}'es recfile. And an additional program that translates it to convenient human readable lines, also acting like @command{tail -f}. It is crucial to read message you want to send not line by line, to be able to send multiline messages in a single post. Closing the FIFO file can be treated as the end of the message. To be able to use rich line editing capabilities or even external editor, you can use great @url{https://github.com/hanslub42/rlwrap, rlwrap} utility in an endless loop. So how all that decisions are composed together? @itemize @item @command{cmd/start} creates @file{debug} and @file{users/status} FIFOs, prepares configuration file for @command{tmux} (actually there is just single path to the command replaced with the real one) and runs it with single window split on two three parts: one just shows debug messages (all raw MM messages), other shows colourized list of non-offline users, another one runs @command{cmd/mmc} itself. @item @command{cmd/mmc} logs in to the server, fetches a list of all known users and channels I am subscribed to. Then it creates necessary @file{users/NAME} and @file{chans/NAME} directories with some basic regular information files (like identifiers and email addresses) with various FIFOs. @item Reading @file{users/.../status} shows you current user's status. @file{chans/.../users} shows currently subscribed users. @item @file{out.rec} is append-only database of passed messages. @file{last} contains the identifier of the last received message. After you log in, it is used to fetch newly appeared messages while you were offline. @item If some user changes its status, or someone is typing, then @command{cmd/mmc} calls @command{cmd/notify} command with corresponding message. Currently that handler just asks @command{tmux} to @command{display-message} for 1.5 seconds. @item If new message comes in, then @command{cmd/mmc} calls @command{cmd/newwin} and tells what window it has to open. @command{cmd/newwin} checks if @command{tmux} has opened it already. Newly created window has the name of the user/channel and is split on two parts: @itemize @item one part contains the output of @command{cmd/rd} piped through @url{http://supercat.nosredna.net/, supercat} (@command{spc}) for colourizing. @item other part holds an endless cycle of @command{rlwrap}-ed @command{cat} piped to corresponding @file{in} FIFO. @end itemize @item Also you can manually open desired chat window by pressing predefined keybinding, that will show you @url{https://github.com/junegunn/fzf, fzf}-backed list of all known users and channels. @item @command{cmd/rd} reads @file{out.rec} file and prints last ten messages (by default) in human readable form. It does not close that file, but regularly checks if it is updated, to immediately print the newly appeared messages. It print bell character with each message, so it sets an alert for window in @command{tmux}. @end itemize Outside that running @command{tmux} user can use @command{cmd/dl} utility to download specified file's identifier. It sends it identifier to @file{file/get} and reads the archive with that file from @file{file/out}. File is sent inside @url{https://pubs.opengroup.org/onlinepubs/9699919799/utilities/pax.html#tag_20_92_13_01, pax archive} to keep its original name and MM's file identifier.