vipirc 0.7.0 - terminal IRC client

An application of ThatIAm.vip (www.thatiam.vip).
Designed by remfan1994.
Source available under the included IALA (Insha-Allah License Agreement).
The full license is in LICENSE.md. Website: https://www.thatiam.vip

QUICK START

    vipirc -h
    vipirc -v
    vipirc --test-mode

These show command help, show the version, and open interactive offline
simulation. For a real connection:

    vipirc --server irc.ircnow.org --channel '#ircnow' --nick tutankh-aten

Quote channel arguments in a shell: an unquoted # can start a shell comment.
The default transport is certificate-verified TLS on port 6697. A server
must actually offer TLS on the selected port. Plain IRC requires --plain.

Every interactive launch begins with:

    Not vegetarian?  www.bloodguiltcurse.net will change your mind

Press an ordinary printable key, Enter, Tab, or a navigation key to dismiss
the welcome. Terminal signal keys keep their meaning: Ctrl-C exits with
status 130; Ctrl-Z suspends, and fg resumes the same welcome screen.
SIGQUIT exits with status 131 after terminal cleanup. Custom terminal
signal characters are respected; other control bytes do not dismiss it.
Without a configured server, startup opens a disconnected workspace with
only vipirc in the header. Open Settings to add a server, or supply --server.
When a connection is requested without a nickname, the terminal prompt
includes your Unix login name as the default; Enter accepts it. Typed text
replaces that default. The server can reject a nickname under its own rules.

If no channel is selected, the initial conversation is the server view,
including the server's welcome messages and message of the day (MOTD).
Configured channels are joined after successful registration and required
authentication. The server can refuse a channel join. Open Servers through
Alt+2 or /servers to manage connections. It supports up to
eight sessions, each with its own channels, queries, and settings.

The client starts ready to type with a visible caret. Enter sends to the
current channel or query after the usual message checks. Server and mentions
views have no implicit chat recipient. Open Command through the vipirc panel,
or type / at chat caret position zero, to use /join or /msg. Tab completes
nicknames and Shift-Tab cycles matches backwards. Alt+1 opens vipirc, Alt+2
Servers, Alt+3 Channels, Alt+4 Queries, Alt+5 Mentions/unread, and Alt+6 File
transfers. Each opens an available panel immediately. Escape from chat opens
vipirc; Escape from an ordinary panel returns to chat. Settings returns to
vipirc on Escape. Arrow keys stay in the editor or panel body.

For a literal message beginning with /, type // followed by the rest of the
message. Bracketed pasted text is always treated as text, even when it
begins with /. Pasting does not send the text automatically.

GETTING HELP

    vipirc -h              command-line summary; --help is equivalent
    vipirc -v              program version; --version is equivalent
    vipirc --manual        this complete manual on standard output
    man vipirc             installed Unix manual page
    /help or /manual       Help inside the running client

The vipirc header destination opens an application panel with Server, Nick,
IALA, Settings, Manual, Command, and Background choices. Select a choice with
Up/Down or k/j and Enter. Server and Nick open the current profile's settings;
Nick selects its nickname field. Disconnected diagnostics show applied
connection choices; connected diagnostics describe the current live session.
IALA opens the complete included license, also offline; Escape, Enter, q, or
Back returns from the license reader to vipirc.

/help, /manual, and /view help open the complete manual directly. It also
shows live connection details, works disconnected, and preserves the prior
chat view, draft, and caret. No chat field or Input/Navigation label is shown.
Up/Down or k/j scrolls a line, Page Up/Page Down scrolls a page, and Home/End
or g/G reaches the beginning/end. Escape, Enter, q, or Back returns to chat.
Pasted text is ignored. View cycling skips the manual. Alt+1 through Alt+6
open other available application categories directly.

MINIMALIST INTERFACE

    vipirc -i
    vipirc --idle --test-mode
    vipirc -i --manual
    1keyirc --test-mode

-i/--idle selects the command-oriented interface while using the same
vipirc configurations and server catalog. The separate 1keyirc executable
uses its own configuration directory and has no curses dependency.

In its log view, / opens a command editor. Another ordinary key opens the
composition screen and retains the character; Enter opens an empty field.
Networking continues while composition hides the log. Escape cancels an
editor or pending review; Escape in the log exits. Ctrl-C terminates,
Ctrl-Z suspends, fg resumes, and Ctrl-D is inert. /background keeps the
client running after detaching; suspension pauses networking.

The default [input] send_mode=direct sends on Enter. send_mode=review
first restores the log with an unsent draft, then a fresh Enter confirms
or Escape cancels. Splitting a message across several IRC lines always
requires explicit approval. Bracketed paste never executes commands or
sends automatically. Tab completes commands or nicknames; Up/Down recalls
matching accepted commands. Log and command history are bounded in RAM.

/help ls lists help topics. /help commands explains command use and lists
commands. /help autoconnect, /help autojoin, /help autoauth, and /help away
give focused instructions. /manual, vipirc -i --manual, and the separate
doc/1keyirc-manual.txt provide the complete minimalist reference. Its
commands and controls differ from the curses interface documented below.

The primary profile's [input] send_mode applies globally in idle mode.
Use /set send_mode direct|review and /save input to persist that choice.
This field is retained when the full interface saves a profile. Native
1keyirc configurations use [history] lines and contain no [interface].
Idle mode uses the primary history limit across all conversations; the
full interface continues to use per-conversation history limits. The
minimalist interface currently has no persistent transcript logging or
DCC transfer UI; DCC remains available in full vipirc.

COMMAND-LINE OPTIONS

    -i, --idle
        Open the minimalist command-oriented interface with the normal
        vipirc configuration. --manual and --help then describe that mode.

    --resume [JOB]
        Resume the sole verified available detached vipirc job, or select its
        number with --resume JOB or --resume=JOB. Multiple candidates are
        listed and require a number. An unverified candidate also prevents
        automatic selection. Requires an interactive terminal. An explicit
        absolute socket path is still accepted for older sessions.
    --sessions
        List this account's local vipirc background jobs without loading
        configuration or requiring a terminal. These management operations
        are separate: do not combine them with one another or with connection
        and configuration options, which belong to a new process.

    -s, --server HOST
        Select a server hostname or numeric IPv4/IPv6 address. Supply a host,
        not an irc:// URL. Use --port for the port.
    -p, --port PORT
        Select a TCP port in the range 1 through 65535.
    -c, --channel CHANNEL
        Auto-join a channel after registration. A comma-separated list or
        repeated --channel options selects several channels.
    -n, --nick NICK
        Select a nickname. Without a selected nickname, the terminal prompt
        offers your Unix login name.
    -C, --config FILE
        Select the primary server configuration and its adjacent server
        catalog. Connection command-line overrides affect this primary
        profile only. The default is
        $XDG_CONFIG_HOME/vipirc/config.ini when XDG_CONFIG_HOME is set, or
        $HOME/.config/vipirc/config.ini otherwise. XDG_CONFIG_HOME must be
        absolute. An explicitly selected file must exist except when it is
        being created with --init-config.
    --tls
        Use verified TLS. The usual default TLS port is 6697.
    --plain
        Explicitly select unencrypted IRC. The usual default plain port is
        6667. Automatic authentication is refused with this transport.
    --ca-file FILE
        Use an explicit PEM certificate authority file for TLS verification.
        Its authorities are trusted in place of the system default store.
    --no-connect
        Start all server sessions without connecting. In test mode, leave
        all simulators stopped. Use /connect for the current server, or
        Connect in the Servers list, when ready.
    --test-mode
        Load normal settings and run interactive, bounded IRC simulation
        inside this process. No network sockets, DNS, credential-file reads, or GPG
        are used.
        Missing server/nickname values do not prompt. See OFFLINE TEST MODE.
    --init-config
        Create a configuration file and exit. Existing files are not
        overwritten. Combine with --server, --channel, and --nick to write
        initial connection values.
    --check-config
        Validate the primary configuration, command-line values, adjacent
        server catalog, and referenced profiles, then exit. This does not
        test server reachability or prove credentials work.
    --manual
        Write the complete manual to standard output and exit.
    -h, --help
        Write command-line help and exit.
    -v, --version
        Write the program version and exit.
    -V
        Compatibility alias for --version.

Long options accept --name=value. Short options accept the normal combined
option syntax. -- ends option parsing; positional arguments are not used.
Command-line values override the selected configuration, which overrides
built-in defaults. Explicit --port is available when a network uses a
different port from the transport's usual default.
Selecting a different --server clears inherited account/server-password
settings and inherited auto-join channels; specify channels for that server.
Additional servers have separate saved profiles. A different --config path
selects a different primary configuration and workspace catalog.

-h, -v, --manual, and --check-config exit without an interactive terminal
or welcome screen. --test-mode cannot be combined with --init-config or
--check-config; either combination is a usage error (exit status 2).

OFFLINE TEST MODE

    vipirc --test-mode
    vipirc --test-mode --config /absolute/config.ini
    vipirc --test-mode --no-connect

The simulator loads the selected configuration and runs the actual
interface, input editor, filters, and applicable protocol/queue handling.
It produces bounded synthetic IRC activity and membership changes. It
opens no network socket, performs no DNS lookup, and reads no password or
CA file. Configured servers are display labels; nothing is sent there.
The primary and saved secondary profiles each run separate simulations.
Servers > New adds more simulated sessions, without changing this mode.

After the welcome screen is dismissed, simulation starts even when the
configuration has autoconnect=false. --no-connect leaves all simulators
stopped until explicitly connected. /disconnect stops the current simulator;
/connect starts only that session's simulation. To connect to a real server,
exit and relaunch without --test-mode.

Missing server and nickname values do not cause prompts. The nickname uses
the Unix login name when valid, or a test nickname otherwise. Configured
channels are used; if none are selected, #test-one and #test-two are supplied.
Server/MOTD remains channel 0. The client starts ready to type. Escape
opens vipirc; Alt+1 through Alt+6 open available category panels. Escape
from an ordinary panel returns to chat; Settings returns to vipirc.
The vipirc panel provides Settings and Command. /channels and /ql also
open the lists; /pm NICK opens a query.

Try fixed-height input, Backspace across rows, resize, paste, the immediate
message-limit warning, and multi-message send confirmation. Inspect
mentions and user lists while simulated events arrive. The same
retained-history bounds and applicable message queue and pacing rules apply.
The local simulator is part of the C client and does not require Python
or an external IRC daemon.

The scheduled event interval is two seconds. A cycle includes channel text,
a nickname mention, a configured custom watch string, a private message,
and a participant joining, changing nickname, receiving voice, and leaving.
All current custom watch strings are tried in rotation, one string per
16-second activity cycle. /watch changes affect the next watch event.
For a stable list of k strings, the sequence repeats every 16*k seconds.
If no custom watch string is configured, the demo gives a /watch example.
/msg NICK TEXT produces a labelled simulated private reply. Channel text
is locally echoed. JOIN, PART, NICK, WHOIS, TOPIC, and AWAY receive simulated
responses; the simulator does not implement every IRC server behavior or
enforce keyed-channel access.

File transfers displays a memory-only sample offer. You can review, reject,
or cancel it; Send and Accept are disabled before any file or socket access.
Closing a secondary test server removes only its runtime row, leaving saved
catalog and profile files unchanged.

/save is disabled in test mode. Interface changes remain in memory and
cannot overwrite real connection settings through that command. To try a
permanent configuration edit, edit the file with your text editor and
restart. This mode does not create or modify a config file automatically.

--check-config is a separate noninteractive syntax/value check. It reads
the primary configuration, catalog, and referenced profiles, reports the
result, and exits. --test-mode
adds interactive inspection of simulated behavior. Neither validates a
real hostname's reachability, TLS certificate, SASL identity, password,
authentication-service behavior, or actual delivery to IRC users.

GLOBAL HEADER AND CHAT CONTROLS

The client starts in chat editing. The header contains categories with
content, always in this relative order:

    1 vipirc               Server/Nick, IALA, Settings, Manual, Command, Background
    2 Servers              configured or retained server sessions
    3 Channels             this server's retained channel views
    4 Queries              this server's separate private conversations
    5 Mentions/unread M/U   timestamped mentions and unread source conversations
    6 File transfers N     retained transfers across all servers

vipirc is always present. A fresh workspace without a server shows only
vipirc. Empty lists take no header space. A parted channel with retained
history and a completed transfer record still count as content. Mentions/unread
is available while any server has retained mention lines or unread source
conversations. M counts the retained mention lines; U counts unread source
conversations. Reading a mention does not remove its retained line.

Visible categories are separated by ' > '. Each keeps its number 1 through
6 even when earlier empty categories are hidden. Alt+number opens that
available category immediately; hidden categories are not created by a
shortcut. Terminals may encode Alt as Escape followed promptly by the digit.
A plain digit in chat is ordinary text. Pasted escape sequences never invoke
these shortcuts.

A solid white divider separates the top bar from the screen below.
The current conversation has its own row below that divider. A query nickname
never replaces Queries. Narrow terminals scroll the header to keep the
selected available category reachable.

Alt+number immediately opens the available panel's body. Arrow keys operate
the editor, list, or actions; they never focus or cycle the top bar. Up at
the first input row stays in the editor. Escape in ordinary chat opens vipirc
without moving the caret; Escape from an ordinary panel restores the previous
chat draft and caret. Escape from Settings returns to vipirc, and the IALA
reader also returns there. Safety dialogs and captured paste keep their own
handling first. A practical setup route is Alt+1 to configure a server,
Alt+2 to connect or join, Alt+3 for channels, and Alt+4 for private queries.

In chat, arrows move the caret, Home/End reaches draft endpoints, and hjkl
and other letters are literal text. Page Up/Page Down scroll the history.
Tab completes a nickname; Shift-Tab cycles matching names backwards. A typed
slash at caret position zero opens the separate Command prompt.

White printable outlines identify selected items. The complete chat-field
border is white while editing is focused. Monochrome terminals retain bold
visible outlines. No Input/Navigation status label or appearance selector is
needed; legacy focus_style entries are accepted only for migration.

Clear and Send sit below the fixed field only when mouse reporting is
available and enabled. Enter sends and /clearinput clears the full draft,
including offscreen text, with or without a mouse. Sending always follows
the same validation, byte warning, and default-No multi-message review.
Send-queue feedback uses the separate status area.

Within server/channel/query lists, Up/Down or k/j selects rows and Enter
opens one. Space switches row/footer action focus while keeping the selected
row. Down past the last row reaches actions; Up returns to rows. Left/Right
or h/l chooses a focused footer action; Enter executes it. With rows focused,
Right/l goes Servers to Channels to Queries, and Left/h returns in reverse.
The channel list always includes server/MOTD as entry 0. Empty Queries can
still be reached with /ql and includes New query...; Join/New opens Command
with /join or /pm prepared. Slash commands also open empty categories that
are absent from the header.

Main chat paste stays literal, including a leading slash, and never sends
automatically. Pasted tabs become spaces. Lists, readers, category navigation,
and safety dialogs ignore bracketed paste. Command and active Settings or
transfer editors accept data according to their sections.

NICKNAME COMPLETION

Tab completes the nickname token at the chat caret. Further Tab presses
cycle matching names in case-aware alphabetical order, wrapping; Shift-Tab
cycles backwards. Matching follows this server's advertised ASCII, strict
RFC1459, or RFC1459 nickname case rules. No lookup or outgoing message is
needed. Ordinary editing ends the current completion cycle.

At the beginning of a draft, completion adds ': '. At the end of a later
word it adds a space. Existing punctuation and following words remain
intact when completing inside a draft. Channels and URLs are not interpreted
as nickname prefixes. A candidate that would exceed the draft's byte or
character bound leaves the entire draft intact. Crossing the smaller IRC
message budget opens the normal early warning; completion never sends.

A channel uses its current roster. A query uses its peer and your nickname.
Server and mention views use peers known from this server's joined channels
and query list. Another server's users are never candidates. Current roster
changes apply to the next completion, without storing an extra user list.

COMMAND PROMPT

Select Command in the vipirc application panel to open it from any chat
caret position. Typing / at chat caret position zero also opens it, even
when a chat draft already exists. The original chat text
and exact caret position remain intact. A slash elsewhere in chat is ordinary
text. Pasted slashes always remain literal chat text.

The prompt has its own editor, available-command predictions, and Run/Cancel
controls. Predictions show implemented names and usage, including aliases.
Right at the end of a command-name prefix completes it and adds a separating
space. Repeated Right cycles matching names. Clicking a candidate completes
the name too. Argument text is preserved and is not predicted. Tab does not
navigate the header or run a command. Nickname completion is in chat. Command names match
ASCII case-insensitively. Unsupported commands are never suggested.

Up recalls progressively older history entries matching the line originally
typed before browsing. Down returns toward newer entries and finally restores
that original line. Matching folds ASCII case in the command name; argument
prefixes match byte-for-byte. Each server owns its own history. Only accepted
commands are remembered; failures remain editable and are not recorded.

History is bounded to 64 entries and 64 KiB of strings including terminators.
Consecutive identical entries are not duplicated; oldest entries are evicted
at either bound. UTF-8 arguments are preserved exactly. No command history is
written to configuration files or disk, and it ends with that server session.

Keyed /join commands are omitted entirely. Messages to common services such
as NickServ/AuthServ/ChanServ, and messages beginning authentication verbs
such as IDENTIFY, AUTH, LOGIN, PASS, or REGISTER, are also omitted. Protocol
authentication commands not implemented by the client cannot enter history.
These omissions keep known credential forms out of later suggestions; they
are not a detector for every arbitrary secret a user might type into text.
Service-message omissions also include harmless messages to those services.

Enter or Run explicitly submits the prompt. An accepted command returns to
main chat editing unless it opens a panel such as Settings, Manual, or a list.
An invalid or refused command stays in Command for correction. Escape or
Cancel returns to chat editing without changing the chat draft or caret.
An empty prompt does nothing. /quit still explicitly exits the application.

Bracketed paste in Command inserts data. CR, LF, and Tab become spaces;
unsupported controls and input-limit violations are reported. Paste never
executes a command or activates a control. Review the text and use a fresh
Enter or Run to submit it. Chat paste remains literal and cannot execute
a local slash command.

Message commands /msg and /me retain their byte-budget warning, paced output,
and default-No multi-message confirmation. // sends a literal leading slash
through the same message path; it is not stored as command history. A
confirmation does not discard or replace the independent chat draft.
Channel Join and Query New actions open Command with /join or /pm prepared.

SETTINGS

Settings in the vipirc application panel, or /settings, opens an app-wide
home containing Interface, every server profile, and New server. Server rows
show their Auto-connect and saved/unsaved state. Select any profile to edit it
without switching the active chat. Edits remain staged until Apply or Save.
The server form scrolls through labelled fields. Up/Down or k/j selects
a field; Left/Right or h/l selects its footer action; Enter activates that
action. Home/End or g/G reaches the first/last field. Letters are ordinary
text while a field editor is open.

    Edit    Apply    Save    Back    Cancel

The editable groups contain:

    Connection fields: Server, Port, Transport, Nickname, Username, Real name,
      Auto-join channels, Auto-connect, Auto-authentication (none/sasl),
      Authentication user, Password file, GPG password file, Plaintext
      password, Server password file, GPG server password file, Plaintext
      server password, CA file.
    Server history: History lines.
    Interface home entry: app-wide User list and Mouse preferences.
    Mentions: existing Watch term fields and Add watch term.
    Ignore: existing Ignore mask fields and Add ignore mask.

Edit toggles a boolean checkbox, opens a two-option choice selector, or
opens a text/number field editor. Enter in an editor stages that field;
it does not Apply, Save, or send chat. Tab stages a valid value and advances
to the next field; Shift-Tab stages it and moves to the previous field.
Invalid values remain editable with their diagnostic. Editing an existing watch term to
empty removes it; Add watch term creates another, within the usual bounds.
Ignore mask fields work the same way; an empty existing mask removes it.

Interface Apply updates Mouse and User list for all current sessions and
future server slots. Interface Save writes only the primary configuration,
atomically and privately, before applying the global values. A failed or
blocked Save leaves every session unchanged. On startup, secondary profiles
use those primary interface choices even if they contain legacy local keys.
History lines remains per server.

Apply validates the staged configuration. It applies interface preferences,
mention terms, ignore masks, and auto-connect in memory, stays in Settings,
and resets the footer action to Edit. The applied values become the new
base for further edits. Apply does not write a configuration file.

Server, transport, identity, auto-join, authentication, and CA changes are
staged connection settings. The next explicit Connect while disconnected,
including /connect, adopts the applied values. Apply does not reconnect an
active session or change its current identity or transport. Use /nick, /join,
and /part for current-session changes. Save retains connection choices for
future launches; /save preserves applied pending choices while saving live
preferences. Trying applied connection settings requires neither Save nor a
restart.

Transport selects TLS (verified) or Plain IRC. It controls encryption of the
network connection, separately from password storage and SASL authentication.
The connection log says whether TLS is required with certificate verification,
or encryption is OFF because TLS is disabled. An unencrypted IRC connection
does not mean that a GPG-encrypted password file has become plaintext on disk.

Save validates and atomically writes this server's full configuration,
then applies live preferences and stays in Settings. Back returns to the
Settings home. The first Save of a new secondary server also creates its isolated profile and startup
catalog entry. Other servers' configurations are not overwritten.
In --test-mode, Save is
disabled; Apply previews changes only in memory. Edit the file externally
and restart to make permanent test-mode configuration changes.

Cancel or Escape closes the entire Settings panel, including from a field
editor or choice popup. Unapplied changes are discarded without another
question. Applied preferences and pending connection values remain in memory;
chat drafts remain intact. Escape from Settings returns to vipirc, including
from a field editor or choice popup. Tab and Shift-Tab move among Settings fields. Creating
or connecting a server from Settings keeps the active chat unchanged.

Changing Server to a case-insensitively different value clears inherited
Authentication, Authentication user, every account/server password source,
and Auto-join channels immediately in the staged form. Enter the intended
credentials and channels after choosing the new server. The active session
is untouched. File fields contain paths; Settings does not read or decrypt
their contents. Inline plaintext password fields are masked while viewing
and editing. They preserve spaces and require a private configuration file.

Bracketed paste is accepted only while a text/number field editor is open.
It inserts data without committing or closing the field. Tabs become spaces;
CR, LF, Escape, and unsupported control characters are rejected. Paste on
the Settings list or in a choice popup is ignored. Review pasted values,
then press Enter to stage the field. Warning and confirmation dialogs keep
their own cancel/acknowledgment behavior before global navigation.

TERMINAL SIGNALS

Ctrl-D is ignored, including when the draft is empty. To exit normally,
run /quit in Command. Custom terminal signal
assignments still take precedence over ordinary key handling.

Unix terminal signal keys remain available. The usual Ctrl-C interrupt
exits without saving drafts; Ctrl-Z suspends the process, and the shell's
fg command resumes it. A suspended client cannot answer the server and may
time out.

RUNNING IN THE BACKGROUND

Use /background, or Background in the vipirc application screen, to keep
IRC connections, direct transfers, histories, and drafts running while
returning to the shell. The program restores the terminal and prints the
numbered resume command for this session, for example:

    vipirc --resume 1

vipirc --resume without an argument resumes the sole verified available
detached job. If several candidates exist, it shows their numbers and requires
a choice. vipirc --sessions lists local jobs without opening configuration or
requiring a terminal. --resume=1 is another accepted spelling. Numbers stay
stable while their jobs exist and may be reused after they exit. An explicit
absolute socket path remains accepted for older sessions.

The session is not saved to disk. A later reboot, explicit
/quit, or process termination ends it. Startup autoconnect profiles are a
separate saved configuration feature.

The first Background action creates one detached worker and a private local
job endpoint. Normal foreground use has no extra helper process or local
socket. Repeated Background actions keep the same worker, number, and endpoint. A
resumed terminal has a small foreground waiter for terminal signals and size
changes. Only one terminal can be attached at a time; an additional resume
attempt reports that the session is busy.

Resume can use a different terminal or SSH login session on the same machine
and Unix account. Terminal capabilities, locale, and geometry are read again.
The resume command requires its input, output, and error descriptors on the
same interactive terminal. It does not make a network listener or require
screen, tmux, or a new language runtime.

Ctrl-C in the resumed application exits normally. A terminal hangup detaches
the worker so its connections continue. Ctrl-Z restores the terminal and
stops the resumed foreground waiter; the worker continues servicing servers.
Use fg to redraw and resume interaction. This is different from stopping an
ordinary foreground process before its first Background action.

If a resolver or credential helper is still running on the first detach,
Background asks you to retry after it finishes. No half-detach occurs.
Normal exit removes the private endpoint. The directory and socket are
owner-only. Discovery checks at most 64 fixed slots with one 1500 ms deadline
for all probes. It removes only verified stale entries whose lifetime lease
is no longer held, without PID lookup or process signalling. Unresponsive
live jobs remain listed as unverified and prevent automatic selection by
bare --resume. Numbered attachment checks the queried job's incarnation before
accepting terminal descriptors, so a reused number cannot redirect it during
handoff. Another process under the same account is within the trust boundary.
Explicit Background also works with offline simulation and creates
only this local endpoint, without enabling IRC or DCC network activity.

SERVERS AND UNREAD ACTIVITY

Up to eight server sessions share this process and terminal. Each has
independent configuration, credentials, nicknames, channels, queries,
mentions, users, retained history, drafts, and cursor/scroll positions.
Background connections keep receiving messages and answering protocol
traffic through the same event loop.

Open Servers with Alt+2, or run /servers in Command.
Up/Down or k/j selects a server row. Enter opens
that server's last view. Right or l on a row opens that server's channels;
Left or h on a channel row returns with the same server selected.

Space switches row/footer focus while preserving the selected server.
Down from the last server row also focuses the footer. Left/Right or h/l
then chooses an action:

    Open    New    Connect    Disconnect    Close    Channels    Away    Back

Enter executes the action for that row. Open switches to the server's last
main view with editing active, keeping its draft. Connect and Disconnect act on
the selected server. Channels opens its channel chooser, with server view 0.
Away toggles the selected registered server between the default away message
Away and return from away; the row reflects the server's acknowledgment.
New, also available as n in the list, opens the new server form. Back or
Escape returns to chat. Space or Up returns from footer to rows. Up at the
first row stays in the list. Home/End or g/G
selects the first/last row while rows are focused. Mouse row clicks open a
server, and footer clicks apply to the selected row.

The primary server is entry 0 and cannot be closed. Disconnect keeps its
views, history, and drafts; accepted direct file transfers continue. A
secondary Close always asks first and defaults to no. Confirming discards
that server's drafts/history, cancels its offers/transfers, and removes its
saved startup catalog reference while keeping the physical profile file.
Closing the current secondary returns to the primary main screen. In test
mode, Close affects only runtime state and never changes saved files.

New server form

Basic fields are Server, Port, Transport, Nickname, Auto-join channels,
and Auto-connect. Its footer is:

    Edit    Add    Connect    Advanced    Cancel

Use Edit to change the selected field. Advanced expands the form to all
startup connection fields, including Username, Real name, Auto-authentication,
Authentication user, all three account/server password-source choices, and
CA file.
This allows credentials to be configured before a first connection. The
Advanced button becomes Basic when expanded. Enter in a field only stages
its value; Escape cancels the whole form. Field paste follows Settings rules.

Fresh servers default to verified TLS on port 6697, a valid Unix login
nickname/username or fallback, and no authentication, credential-file paths,
CA override, channels, watch strings, or ignore masks. Only interface
preferences copy from the primary profile. Auto-connect defaults to false.

Add validates and creates a disconnected session, even if Auto-connect is
checked. Connect validates, creates, and connects immediately. Both switch
to the new server's main screen. Neither writes configuration. Use /save or
Settings > Save explicitly to retain this profile across launches.

Activity indicators

Server, channel, and query rows start with new N !M: unread activity and
unread mentions. The ! marker is explained in the list header. Counts above
999 display as 999+ while the internal counters remain exact. The main
unread-view count includes background servers.

Showing a main conversation clears only that source view's counts. A list
covering the current conversation does not mark arriving text read. Server
totals aggregate source server/channel/query views and exclude the copied
Mentions feed and Manual, avoiding duplicated counts. Opening Mentions
marks its feed read independently and does not clear source conversation
counts. Outgoing local echoes do not add unread activity.

Alt+5 and /unread open a workspace-wide Mentions/unread browser. It groups
Unread conversations and Mentions beneath nonselectable group and server
headings. Unread entries identify their Server, Channel, or Query source;
mention entries show the complete wrapped line with its original timestamp.
M in the header counts retained mention lines; U counts unread source
conversations. Mention copies and Help never duplicate unread source counts.

Enter or a mouse click opens the exact source server and conversation. A
closed source is marked and refused; a newly created view with the same name
cannot take its place. Up/Down or k/j selects entries; Home/End or g/G selects
the first/last entry. Page Up/Page Down scrolls a long selected mention before
moving to adjacent entries. Back or Escape returns to main chat. This browser
supplements the separate channel/query lists without changing their numbering.
/mentions still opens the current server's original mention feed.

VIEWS AND USERS

Every server has its own server/MOTD entry 0, channel list, query list,
mentions feed, and rosters. Channel and query headers identify their server.
The server view contains registration, MOTD, connection, and error messages.
Each channel or private conversation has a separate view. The mentions view
collects matching received lines with their original displayed timestamps,
source conversation, sender, and full message text. A long line wraps in
the display; the line's stored text remains complete within protocol bounds.

    /servers               open the workspace's server list
    /unread                open the combined unread/mentions browser
    /server                switch to the current server's MOTD view
    /mentions              open the current server's original mention feed
    /channels              open the numbered channel chooser
    /channel N             switch by channel-chooser number; 0 is server
    /channel #NAME         switch to an open named channel
    /ql                    open the separate query list
    /pm NICK               open/switch a private view without sending text
    /next                  next view
    /prev                  previous view
    /users                 toggle the channel user list
    /users on              show the channel user list
    /users off             hide the channel user list
    /users up              scroll the channel roster upward
    /users down            scroll the channel roster downward
    /mouse [on|off]        toggle mouse controls, or explicitly enable/disable
    /clear                 clear the current view's stored lines
    /clearinput            clear the current conversation's complete draft

Alt+5 opens the combined Mentions/unread browser. /users and Settings > Interface share the
User list preference. The user list belongs
to the current channel; server and private conversation views do not have
a channel roster. A small terminal may hide the sidebar to leave usable
space for the conversation. Expanding the terminal makes room for it again.
User list membership follows server JOIN, PART, QUIT, NICK, KICK, and NAMES
messages. Network-defined privilege prefixes identify channel privileges.
Incoming private messages create a new query view only while fewer than
eight query views exist. Further unsolicited queries remain visible with
full context in server and mentions. Explicit /pm or /msg can create more query
views, subject to the per-server 32-view limit.

CHANNEL CHOOSER AND CLOSING CONVERSATIONS

Use the Channels header destination, /channels, or Right/l on a selected
server row.
Entry 0 in Channels is always the server's MOTD view. Other entries are that
server's channel views, including left channels whose history is retained.

Up/Down or k/j selects a row; Enter opens it. Left or h while a channel row
is focused returns to Servers with its server selected; Right or l opens
Queries. Space switches to the footer without changing the selected channel;
Down from the last row also focuses it:

    Open    Join    Part    Close    Back

Left/Right or h/l chooses an action only while that footer is focused.
Enter activates it for the selected row. Space or Up returns to rows; Up
at the first row stays in the list. Join opens
the separate Command prompt with /join prepared, preserving chat drafts
and caret positions. Part leaves the channel and keeps history; Close removes
the view. Back or Escape returns to main chat editing.

Home/End or g/G reaches the first/last row. Direct aliases remain: p parts,
c closes, and o opens the Join prompt. A mouse click on a row opens it;
a footer click acts on the selected row. Narrow action bars keep their
focused action visible with side arrows.

Closing a joined channel first requests PART. Its retained history and
draft are removed, and queued chat for that destination is cancelled; one
already in-flight message may finish. A close that would discard a nonempty
draft asks first, defaulting to No. The server entry cannot be parted or
closed; /disconnect ends its connection.

/close [NAME|CHANNELNUMBER] also closes a channel or query; without an argument
it closes the current conversation. Server and mentions views cannot be
removed. Channel numbers can change after closing a channel; use the current
list. /views aliases /channels. /view N uses the same channel numbering;
/view NAME selects a named view. Help returns through Back or Escape.

QUERY LIST

Use the Queries header destination, /ql, or Right/l on a channel row. This
list contains only the current server's private conversations. The query
name remains on the conversation row and never replaces a header category.

Up/Down or k/j selects a row and Enter opens it. Left or h on a row returns
to Channels. When empty, a New query... row opens Command with /pm prepared;
Left still returns to Channels. Space switches row/footer focus while keeping
the selected row, and Down from the last row also reaches the footer:

    Open    New    Close    Back

Left/Right or h/l chooses an action while the footer is focused; Enter
activates it. Space or Up returns to rows; Up at the first row stays in the list.
New opens Command with /pm prepared
and preserves the existing chat draft. Close removes the selected query;
a nonempty draft requires confirmation, defaulting to No. Back or Escape
returns to main chat editing.

Home/End or g/G selects endpoints. Direct aliases are c for Close and o or
n for New. Mouse row clicks open a query; footer clicks act on the selected
row. Narrow action bars keep the focused action visible with side arrows.

/pm NICK opens or selects a query without sending anything, even disconnected.
Chat editing is ready immediately afterward. /msg NICK TEXT sends directly.
Close a private view by nickname with /close NICK.

MENTIONS AND WATCH STRINGS

Your current nickname is watched automatically. Nickname matching follows
the IRC server's advertised case mapping and nickname boundaries. A nickname
change updates this automatic match.

    /watch add project name
    /watch remove project name
    /watch list

Custom watch values are literal substrings, not regular expressions or
shell patterns. IRC/ASCII letter and symbol case rules are used; non-ASCII
characters match exactly. Up to 32 custom values of 127 UTF-8 bytes each
are accepted. Use /save during normal operation to preserve changes in the
selected configuration. In test mode, changes remain in memory.
Mentions are retained in memory, subject to the history limits. They are
not a permanent notification archive or an on-disk log.
Timestamps are local receipt dates and times, in YYYY-MM-DD HH:MM:SS form.

CONVERSATION COMMANDS

    /join CHANNEL [KEY]     request to join one channel, optionally with a key
    /part [CHANNEL]        leave a specified channel or the current channel
    /close [NAME|NUMBER]   close a channel/query; number is a channel number
    /pm NICK               open/switch a private view without sending text
    /msg TARGET TEXT       send text to one nickname or channel
    /me TEXT               send an IRC action to the current conversation
    /nick NICK             request a different nickname
    /away [MESSAGE]        set away with text; without text, clear away
    /back                  clear away status; takes no argument
    /whois NICK            request information about a nickname
    /topic                 request the current channel topic
    /topic TEXT            request a new current-channel topic
    /connect              connect this disconnected server with applied settings
    /disconnect           disconnect this server, keeping its views/drafts
    /dcc or /transfers     open the shared File transfers screen
    /cancel               discard queued chat not yet being transmitted
    /background           keep running and return to the shell
    /quit                 exit all server sessions and transfers
    /settings             edit app-wide preferences and any server profile
    /save                 write current settings; disabled in test mode
    /set autoconnect on    enable connection at future startup after saving
    /set autoconnect off   disable it

/away MESSAGE sends one standard AWAY message. Text is limited to the
current wire limit minus 8 bytes (504 bytes at the usual 512-byte limit);
oversized text or controls are rejected, never split. /away with no text
and /back clear away. These require registration. The indicator changes
only on server acknowledgments and resets on disconnect/reconnect.
The server list's Away action sends Away as the message or clears an
acknowledged away state, preserving the view and draft. A disconnected
server must connect first. Edit ignored senders in the Settings Ignore
fields, or use the local /ignore and /unignore commands.

/join accepts one channel and at most one key token. Keys must be printable
ASCII without spaces, colon, or comma, and the complete JOIN must fit the
wire limit. The key is not logged or saved; only the channel name enters
auto-join. Re-enter the key when needed after reconnecting or restarting.
The offline simulator acknowledges away changes and accepts transient
join keys, but does not test a real channel's key or admission policy.

The server decides permissions, nickname availability, channel admission,
and whether topic changes are allowed. Local command acceptance does not
guarantee server acceptance or delivery to another participant.
/cancel cannot recall a message already transmitted; one in-flight message
may still finish. /join and /part update the auto-join selection; /save
preserves that selection for future launches unless pending Settings startup
choices override it.
/part also discards queued text for that channel while retaining the view
and its history. A message already in flight may finish before PART.

LOCAL IGNORE FILTERS

    /ignore or /ignore list       list masks in the server view
    /ignore MASK                 add a mask; /ignore add MASK also works
    /unignore MASK               remove it; /ignore remove MASK also works
    /ignore clear                remove all masks

These local commands work disconnected. Use /ignore add NICK for nicknames
literally named list, add, remove, or clear. Up to 32 masks of 127 ASCII
bytes each are accepted. A plain mask must be an exact valid nickname.
Wildcards require full nick!user@host form with three nonempty components;
for example, *!*@*.example. Within each component, * matches zero or more
bytes and ? matches one byte. Other permitted bytes are literal; there are
no regex classes, escaping, or shell expansion. Nick uses IRC case rules;
user and host ignore ASCII case. Whitespace, controls, and non-ASCII are invalid.
Removal compares stored patterns under those case rules; it does not expand
wildcards to remove other masks.

Only incoming user-originated PRIVMSG/NOTICE is filtered, before mentions
or query creation. A source needs an explicit user prefix; nickname-only
masks can match incomplete user/host details, while full masks require all
three parts. Bare server notices and all protocol/membership state remain
visible. Existing history is retained. Filtering is local, not a server ban.
Settings edits the same list; Apply acts live. /save or Settings Save persists
it in normal mode; test-mode edits stay in memory. Config repeats mask= in
[ignore].

FILE TRANSFERS

The File transfers header destination, /dcc, and /transfers open the same global
transfer screen. Records identify their originating IRC server. Up/Down
selects a transfer; Left/Right selects an action; Enter executes it:

    Accept    Reject    Send...    Cancel transfer    Back

Alongside arrows, j/k selects rows, h/l selects actions, and g/G selects
endpoints. Mouse
rows select records and action clicks execute the selected action. The
screen needs at least 12 rows by 20 columns for transfer review. Escape from
any transfer screen returns directly to main chat editing without discarding
chat drafts or stopping accepted transfers. Alt+number opens available global destinations.

This release supports active classic IPv4 DCC SEND only. It does not support
DCC CHAT, resume, passive/reverse transfers, automatic acceptance, automatic
address discovery, or automatic port forwarding. A transfer can contain at
most 4,294,967,295 bytes. Received files are never opened or executed for you.

DCC transfers are unencrypted direct peer connections, independent of IRC
TLS. The protocol does not cryptographically authenticate a connecting peer.
An outgoing offer discloses its advertised IPv4; accepting an offer reveals
the receiving host's IP to the peer. Check the sender, intended file, byte
size, and displayed endpoint before approving each transfer.

Receiving

An incoming offer is stored without opening any file or socket. Reject
refuses it without creating either. Accept in the list opens a review form
with Directory and Save as fields and this footer:

    Edit    Accept    Cancel

Review the peer endpoint and size, edit the destination if needed, then
choose the form's Accept to start. Enter in a field stages it; it does not
accept the offer. Cancel returns to the list. Field paste inserts data only;
unsupported controls cannot commit it. Paste outside a field is ignored.

The default directory is $XDG_DATA_HOME/vipirc/downloads when XDG_DATA_HOME
is absolute, otherwise $HOME/.local/share/vipirc/downloads when HOME is
absolute. Without an absolute base, enter a destination explicitly. Missing
destination ancestors are created with mode 0700 only after Accept. The
final directory must be private and owned by you. A new regular file uses
mode 0600; existing files, symlinks, and '..' paths are refused.

The offered or chosen basename must be visible and nonhidden, with no path
separators, control/bidirectional-formatting characters, or quotes. Quoted
wire filenames may contain internal spaces. Failed or cancelled partial
files are removed only if they still identify the file created for that
transfer; a replacement file is not removed.

Sending

Select Send... to open a form containing Nickname, Source file, Advertised
IPv4, and Listen port. A current query supplies its nickname as a default.
The form names the IRC server through which the offer will be sent. Its
footer is Edit, Offer, Cancel. Offer explicitly starts the listener and
queues the offer through that registered server's paced chat path.

Source file must identify an existing regular file; symlinks and '..'
components are refused. Prefer an absolute path. Enter the IPv4 address the
receiver can reach. Listen port 0 chooses an available local port; an
explicit value is from 1 through 65535. Behind NAT, use the appropriate
advertised address and a forwarded port. vipirc does not discover the
public address, configure UPnP, or arrange forwarding.

With SSH, all paths, HOME/XDG download directories, listening/advertised
addresses, and peer connections belong to the host running vipirc. That
may be the remote SSH host. The terminal emulator's local filesystem and
network address are not used for these transfers.

Lifecycle and bounds

Accepted transfers continue while chatting, switching servers, or
Disconnecting IRC. Cancel transfer stops one transfer. Closing its server
cancels that server's offers and transfers; quitting stops all of them.
Cancellation, failure, or expiry also removes a still-queued outgoing
offer. An offer already sent or in flight cannot be recalled.

The workspace permits eight pending offers, four active/listening/connecting
transfers, and twelve retained transfer records in total. Completed or failed
records are recycled oldest-first only when full; transfer IDs are not
reused during a run. Pending offers expire after five minutes. Transfers
stop after two minutes without progress. File data is streamed in bounded
buffers, with cumulative 32-bit acknowledgments.

In --test-mode a memory-only sample offer permits list/reject/cancel review.
Send and Accept are disabled before any filesystem or socket access. Real
file transfers require restarting without --test-mode.

INPUT EDITING

These keys apply while editing the main chat draft:

    Enter                  send or review the composed text
    Left                   previous character group
    Right                  next character group
    Up / Down              move between wrapped visual input rows
    Home                   beginning of the complete composition
    End                    end of the complete composition
    Backspace              remove the previous character group
    Delete                 remove the character group under the caret
    Tab / Shift-Tab        complete next / previous matching nickname
    Esc                    open vipirc; ordinary panels return to chat

Alt+1 through Alt+6 open the available category panels. Escape from Settings
returns to vipirc. Up at the first wrapped input row stays in the editor.

Typed Enter or Send below the field submits; explicit newlines can be
composed through bracketed chat paste. Pasted tabs become spaces without
changing focus. /clearinput or Clear below the field clears the entire
draft, including offscreen text, without changing input focus. Clearing
never sends text and requires no preliminary select-all step. A typed slash
at caret position zero opens Command while preserving this draft; a slash
later in the line or any pasted slash remains ordinary chat text.

The composition is a flat logical buffer. Screen wrapping does not insert
characters. Backspace at the beginning of a wrapped row removes the last
character of the preceding row. Resizing the terminal retains the text and
cursor position.

Input height is fixed for the current view and its protocol byte budget.
For B ordinary-message payload bytes and W usable terminal columns, it
reserves floor(B/W)+1 rows, including the caret cell. The border occupies
the outer columns; W is the space inside it. A budget of 465 bytes at 99
usable columns reserves five rows. Small terminals clamp the height to
available rows. Views without a chat recipient use a one-character recipient
allowance when calculating their height.

Typing and deleting do not grow or shrink the chat field. Longer drafts
scroll within it to keep the caret visible. Command has its own fixed editor;
opening or running /msg or /me does not resize or replace the chat draft. A terminal
resize, view switch, or actual protocol-budget change recalculates the
height. The draft and cursor position remain intact.

UTF-8 is used for input and messages. Set a UTF-8 locale so the terminal and
the curses library agree about display widths. ASCII is already its
one-byte subset; no manual encoding switch is needed. SSH does not
change the encoded message length. On each remote host, inspect the session:

    locale
    locale charmap
    locale -a

The first two show locale settings and character encoding; locale -a lists
installed locales. The effective LC_CTYPE on the host running vipirc should
use an installed UTF-8 locale matching the terminal. Names vary across
systems, so check each SSH host. TERM identifies terminal capabilities,
not encoding. The client does not guess terminal encoding or transcode
legacy character sets.

The active LC_CTYPE is respected. A UTF-8 locale enables Unicode editing.
A non-UTF-8 or invalid locale selects ASCII terminal mode. The welcome
screen explains the mode. ASCII
typing works; non-ASCII input is refused with a clear status message.
Incoming non-ASCII code points display as '?' without changing the stored
network text. The client does not force a locale or change terminal
settings. Select an installed UTF-8 locale and restart for Unicode use.

A base character and its following zero-width marks move and delete
together. Full Unicode grapheme segmentation, including indivisible
multi-character emoji sequences, is not implemented. Unsupported glyphs
receive a visible replacement where needed.

The composition accepts up to 8,192 Unicode scalar values and 16,384 UTF-8
bytes. These are draft-storage bounds; the much smaller message budget
below determines warnings and splitting. The first storage limit reached
applies. Invalid UTF-8 and terminal controls are rejected. Pasted newlines
remain visible in the composition and are considered when calculating how
many IRC messages would be needed.

MOUSE CONTROLS

Mouse controls are enabled by default when curses and the terminal support
mouse events. /mouse toggles the preference; /mouse on or /mouse off sets it.
Settings > Interface > Mouse edits the same value. The configuration key is [interface]
mouse=true or mouse=false. To retain this app-wide preference, use Settings >
Interface > Save, or /save while the primary server is selected. /save on a
secondary server writes only that server's profile; its legacy mouse value
does not override the primary preference at startup. The same persistence
rule applies to the app-wide User list preference.

Click a global header category to open it. The conversation identity below
the header is a label, not a substitute for the Servers or Channels control.
Click inside the chat-field border to place the caret and type. Clear below
the field erases the entire draft without changing input focus. Send follows
the same validation, length warning, and split confirmation as typed Enter.
Clear/Send are hidden when mouse handling is off or unavailable. Enter and
/clearinput remain usable. Clicking a nickname in chat or the roster opens
its context menu, including Whois and Query. Clicking a #channel joins it
if necessary or switches to its existing joined view. The displayed token,
not a later replacement at the same coordinates, determines the action.

A server/channel/query row click opens the row; a footer click acts on the
selected row. The wheel changes row selection. Space switches row/action
focus in those lists; Up at the first row stays in the list. Back or Escape returns
to main chat. Settings and transfer
screens retain their own field and action controls.

Over conversation history, each wheel step scrolls three visual rows; over
the user roster it scrolls three users. The main chat display needs at least
9 rows and 20 columns. The global header and conversation row sit above
history, the fixed chat field, and the conditional Clear/Send controls.
Empty header categories are omitted; counts append to categories with
content. A narrow header keeps the selected destination visible.

The terminal and any SSH multiplexer must forward mouse events. Availability
depends on curses, TERM, and the terminal; keyboard operation remains usable.
Mouse clicks do not acknowledge the early length popup or multi-message
confirmation. Those require their displayed keyboard choices. Mouse handling
does not open URLs or transfer clipboard text.

Command has explicit Run and Cancel controls. A pasted click sequence or
pasted newline cannot activate them. Enter/Run must be a fresh action after
the paste has ended. Clicks from a previous screen layout are not reused as
actions on a newly opened screen.

MESSAGE LENGTH AND FLOOD PREVENTION

Ordinary IRC protocol lines are limited to 512 bytes, including CR and LF.
That is a wire-line limit, not a limit of 512 user-visible characters.
ASCII uses one byte per character. A Unicode code point uses one to four
UTF-8 bytes, and a displayed glyph can contain multiple code points.
Command, destination, and relay prefix also take space. For a relayed
message of the form

    :nick!user@host PRIVMSG target :text<CR><LF>

the budget used by vipirc is

    B = L - (len(nick) + len(user) + len(host)
             + len(target) + len("PRIVMSG") + 9)

L is normally 512, reduced by a recognized smaller server LINELEN value.
Lengths in this expression are bytes. IRC actions have an additional
envelope, whose bytes are also subtracted. Until the full relay identity is
known, conservative identity allowances reduce B. Different destinations
and identity changes can therefore change the current payload budget.

While editing, a popup appears as soon as the longest logical payload line
reaches B bytes, or the draft already needs multiple messages:

    Message limit reached (B bytes).
    More text will need multiple chat lines.
    Enter/Esc: keep editing. Nothing sent.

If the draft already needs multiple messages, the middle line instead says
"This draft needs multiple chat lines." Enter or Esc returns to Input mode;
neither sends the draft. Other keys cannot dismiss the popup, and a short
key-repeat guard protects acknowledgment. The warning is shown once per
threshold crossing. Editing back to one message below the byte limit arms
it again. /msg, /me, and // are measured by their actual outgoing payload;
other local commands do not trigger this warning. Bracketed paste is
checked after the paste finishes and remains intact within the input bounds.

When Enter submits a composition needing more than one message, the client
presents a separate send confirmation:

    This text needs N IRC messages. Send all? [y/N]

Enter or n declines. Sending requires an affirmative y. Splits occur only
between complete UTF-8 characters, with nonempty message text preserved.
Explicit newlines separate messages; empty lines are skipped. No split is
sent before confirmation. Local slash commands must remain single-line;
compose multiline chat in the selected conversation instead.
Accepted chat messages are paced at least 1.2 seconds apart; the bounded
send queue holds at most 64 messages. Server flood rules can be stricter.
Protocol control traffic such as PONG is handled separately from chat.

The network can impose additional rules or reject messages. vipirc keeps
the ordinary 512-byte compatibility ceiling; it does not assume that a
server will accept a larger line merely because an extension exists.

CONFIGURATION

Generate an editable starting point:

    vipirc --init-config --server irc.ircnow.org --channel '#ircnow'

Edit the file with your preferred text editor. Validate it before launch:

    vipirc --check-config

One file describes one server profile. --config selects the primary
profile and its adjacent catalog of saved secondary profiles. Up to eight
server sessions share a process. Separate --config paths can still open
independent workspaces in different terminals.

Recognized sections and keys:

    [connection]
    server=irc.ircnow.org
    port=6697
    tls=true
    nick=tutankh-aten
    username=
    realname=vipirc user
    channel=#ircnow
    autoconnect=true
    auth=none
    auth_user=
    password_file=
    password_gpg_file=
    password=
    server_password_file=
    server_password_gpg_file=
    server_password=
    ca_file=

    [interface]
    user_list=true
    mouse=true
    history_lines=500

    [mentions]
    word=project name
    word=another literal phrase

    [ignore]
    mask=spammer
    mask=*!*@*.example

The nickname and IRC username are different fields. An empty nickname is
prompted at interactive startup. The username defaults from your Unix
account. realname is the descriptive IRC USER field; it need not be your
legal name. channel is a comma-separated auto-join list, without spaces.
An empty channel value leaves you in the server view.

auth accepts none or sasl. With sasl, auth_user is the network account name
and exactly one of password_file, password_gpg_file, or password must be
nonempty. The optional server PASS password independently selects one of
server_password_file, server_password_gpg_file, or server_password. More
than one source for either credential is an error; there is no fallback.
Server PASS is separate from the nickname account. Both authentication
paths require verified TLS. See AUTOMATIC CONNECTION, JOIN, AND AUTHENTICATION.

Arrows and hjkl always navigate while a text editor is not active. Older
[interface] keymap=original and keymap=vim entries are accepted for migration
but have no effect and are omitted when saving. Other keymap values are
invalid. /keymap is a compatibility command that explains the fixed behavior;
it cannot select a different mapping.

Legacy focus_style=reverse and focus_style=brackets are accepted but ignored,
and saving omits the key. Other values remain invalid. Focus has one white
outline, with a bold fallback on monochrome terminals; no selector is needed.
history_lines accepts 50 through 5000 retained lines per view, default 500.
The additional per-server 8 MiB history text cap can evict older lines sooner.
Boolean values accept true/false, yes/no, or 1/0 in lowercase. Unknown
sections, unknown keys, invalid values, and oversized values are errors
with a configuration line number where applicable. Most duplicate keys
use the last value; repeated mentions word and ignore mask entries add values.

Lines starting with # or ; after leading whitespace are comments. There
are no inline comments: # inside channel=#ircnow is part of the value.
Leading and trailing value whitespace is trimmed, except for the two inline
password keys described below. Quotes, backslashes,
environment-variable expansion, ~ expansion, and shell evaluation are not
configuration syntax. Paths are literal; prefer full absolute paths.
Settings Apply and configuration saving reject leading or trailing ASCII
spaces in ordinary text values, including watch phrases and credential-file paths.
This prevents a saved value from changing when reloaded. Interior spaces
remain valid where the field permits them. Hand-written INI padding keeps
the trimming rule above; quoting or escaping cannot preserve outer spaces.

password and server_password are literal exceptions: every byte after the
first '=' belongs to the password, including leading/trailing spaces,
additional '=', '#', and ';'. Only the line ending is removed. Do not add
quotes, escapes, or an inline comment. Empty means no inline source; a
password consisting of spaces is nonempty. Controls and newlines are invalid.

/save during normal operation generates the whole selected configuration
again, preserving any pending connection choices applied through Settings. It preserves the supported settings, and replaces hand-written
comments and formatting.
Changes to the file are loaded at the next launch. Keep any explanatory
notes you want to retain outside the generated file.
The command is disabled in --test-mode; edit the file and restart instead.

Generated files have mode 0600. Their final parent directory must belong
to you and have mode 0700. Existing config files must belong to you and
must not be writable by other users. Symlinks in a config or secret path,
including directory components, and '..' path components are refused.
If either inline password is nonempty, the configuration must be a regular
file owned by you with exactly mode 0600 or 0400. Save always writes 0600.

SAVED SERVER PROFILES

For primary path P, the adjacent P.servers catalog lists up to seven
secondary profiles in the private P.d directory. For the default path,
these are config.ini.servers and config.ini.d beside config.ini. Catalog
syntax is [servers] followed by repeated profile=ID entries. Generated names
use server-<24 lowercase hexadecimal characters>.ini. Manual IDs may contain
1 through 63 ASCII letters, digits, underscores, hyphens, or dots; the first
character must be a letter or digit, and consecutive dots are forbidden.
Directory components and arbitrary paths are not accepted as profile IDs.

Servers > New creates no file. Its first explicit /save or Settings Save
creates a separate mode-0600 profile in the mode-0700 directory and registers
it in the catalog. Subsequent saves update that server's profile. Saving
a secondary never replaces the primary configuration. Startup catalog
updates are locked. Invalid catalog/profile entries produce visible errors;
healthy profiles remain usable.

Close removes a secondary's catalog reference but keeps its profile file.
The primary cannot be closed. --check-config checks the selected primary,
catalog, and referenced profiles without connecting. Connection command-line
overrides apply only to the primary. --no-connect suppresses startup for
all profiles. In test mode, Save is disabled and Close changes runtime only.

AUTOMATIC CONNECTION, JOIN, AND AUTHENTICATION

Settings lets you edit all startup profiles without switching chat. Open a
server from its home screen, enable Auto-connect, set Auto-join channels and
that server's authentication, and Save. Repeat for each desired startup
server. A disabled Auto-connect keeps the saved profile available without
starting it. New server from Settings can add or connect without changing
the active conversation. No other server's credentials are inherited.

An explicitly supplied primary --server starts a connection. Each saved profile with autoconnect=true connects at startup.
--no-connect overrides startup connection for all profiles. Without automatic
connection, /connect starts the current server; Connect in Servers starts
the selected row. Each server authenticates only with its own configuration.

The channel setting supplies the auto-join list. For automatic account
authentication, configure the account registered with that network:

    [connection]
    tls=true
    auth=sasl
    auth_user=your_registered_account
    password_gpg_file=/home/yourname/.config/vipirc/sasl.gpg

There are three explicit sources for each credential:

    SASL account                  Server PASS
    password_gpg_file              server_password_gpg_file
    password                      server_password
    password_file                 server_password_file

The *_gpg_file settings select encrypted files; the *_file settings select
private plaintext files. password and server_password put plaintext in the
configuration itself. Set only one source in each column and leave the
other two empty. There is no extension detection or fallback to another
source. Settings exposes all sources and masks inline password fields.

Plaintext and decrypted passwords must be one nonempty line, optionally
followed by LF or CRLF, without control bytes. The SASL limit is 1024 bytes;
server PASS is limited to 503 bytes so its IRC line fits the wire limit.
Files of either kind must be regular, owned by you, and mode 0600 or 0400.
Symlinks and '..' path components are refused. Plaintext files can be made
with a text editor; no password is accepted as a vipirc command-line option.

For an inline password, use password= followed immediately by its literal
value, or server_password= for server PASS. Leading/trailing spaces, '#',
';', and '=' are preserved. There is no quote/escape or inline-comment
syntax. A configuration containing an inline password must be mode 0600
or 0400 and owned by you; generated configuration is 0600. It remains
plaintext in that private file and in session configuration while needed
for reconnect or Save.

Encrypted files must contain a single integrity-protected OpenPGP message
and be at most 65536 bytes. GPG is optional; its executable must be named
gpg in PATH and support the fixed options (GnuPG 2.2.20 or newer). vipirc
starts it directly after verified TLS, without a shell. Decryption has a
five-second deadline and bounded memory output, with no plaintext temporary
file. The interface and other sessions continue while it runs. A failed,
locked, invalid, oversized, or timed-out credential stops authentication.

The helper uses --no-options, --batch, --no-tty, --pinentry-mode error,
--no-autostart, and options disabling key retrieval, import, and dirmngr.
It never asks for a GPG passphrase inside the terminal interface. Prepare
the key and unlock the needed agent outside vipirc, for example:

    gpg --output /dev/null --decrypt /absolute/password.gpg

Then run /connect in vipirc. The existing agent must be able to supply the
credential without interaction. No password or GPG passphrase belongs in
the command above. With SSH, the files, PATH, GnuPG home, and agent are in
the environment of the host running vipirc. A different remote session may
have a different agent/cache and require a separate unlock.

--check-config validates source selection and configuration-file privacy
without opening credential sources or starting GPG. --test-mode also never
reads credential files or decrypts; configured inline passwords are parsed
but not used. These modes cannot prove that a real credential is usable.

SASL PLAIN is sent only after successful TLS verification. The server must
support that authentication method. Required authentication failure stops
the connection; channels are not silently joined under an unauthenticated
identity. The client does not register a nickname account on your behalf.
Nickname-service command formats are network-specific; automatic account
authentication in this release uses SASL.

SECURITY AND RESOURCE BOUNDS

TLS verifies the certificate chain and the requested hostname or numeric
address. There is no certificate-verification bypass or silent downgrade.
Plain IRC is available only through an explicit setting; it exposes IRC
traffic to observers on the connection path and cannot use saved secrets.
TLS protects the client-to-server connection, not end-to-end chat privacy.

Incoming IRC data is untrusted. Unsafe control sequences and formatting
are sanitized before display. Input and network buffers are bounded. The
client does not execute received text, launch URLs, run shell commands,
load scripts or plugins, or reply automatically to CTCP requests. Action
messages are displayed as text. DCC SEND offers require explicit per-file
review and acceptance; their direct connections are not encrypted by TLS.

Limits in this release:

    Server sessions per process           8
    Views per server, including builtins  32
    Users stored per channel           4096
    Custom mention strings per server     32
    Ignore masks per server               32
    Queued chat messages per server       64
    Command history entries per server    64
    Command history text per server  64 KiB
    Retained history text per server   8 MiB
    Input Unicode scalars per draft     8192
    Input UTF-8 bytes per draft        16384
    Pending DCC offers, whole workspace    8
    Active DCC transfers, workspace        4
    Retained DCC records, workspace       12

The history cap applies per server, not as a total-process memory cap.
At eight sessions the maximum retained history text is 64 MiB. Server state
is allocated as needed; fewer sessions do not reserve eight full histories.
Libraries, view metadata, user lists, input, and transport use more memory.
History and mentions are not written to disk. Settings and secret files
are local files; other software with your account's privileges can read
them. No client can guarantee safety against every hostile server or a
compromised terminal, operating system, or library.

TROUBLESHOOTING

No connection: inspect /server for the concrete error. Verify the hostname,
port, network access, and whether the port actually offers TLS. /connect
retries manually. Verify a certificate failure's cause; do not send account
credentials over plain IRC to work around it.

Authentication failure: check the registered account name, the selected
credential source and private permissions, and whether the network supports SASL PLAIN.
A server PASS password is separate from a nickname-account password.

GPG failure: check gpg --version (2.2.20 or newer), the encrypted file's
ownership/mode/size, and that it contains one integrity-protected message
with a valid one-line password. Unlock it outside vipirc with
gpg --output /dev/null --decrypt /absolute/password.gpg, then retry /connect.
A locked or absent agent cannot open a passphrase prompt inside vipirc.
There is no automatic fallback to a plaintext source.

Nickname rejected or in use: choose another nickname with /nick when the
server permits it, or apply a new nickname in Settings and explicitly Connect
while disconnected. Save that choice to retain it for future launches.

Empty channel view: inspect /server for join refusal, an invite-only or
restricted channel, or authentication requirements. /join requests a join;
it does not override server permissions.

Unusual text widths: use a UTF-8 locale, correct TERM setting, and a terminal
font with the desired glyphs. Unicode width choices can vary by terminal.
Resize the terminal to refresh geometry. Enlarge the window if the sidebar
or input is cramped; the draft and caret are preserved.

Config save refused: use a private directory owned by your account, with
mode 0700, and a normal file path without symbolic links or '..'. /save
does not follow links to another file. Generated configuration is mode 0600.
In --test-mode, saving is deliberately disabled for the whole session.

PLATFORMS, BUILD, AND LICENSE

The target is Unix-like systems, including Linux in ChromeOS's Linux
environment and the BSDs. Requirements are a C11 compiler, POSIX interfaces,
a GNU/BSD getopt_long interface, wide-character curses, and compatible TLS
headers/libraries. There is no language runtime dependency for the client.
Python 3 is used for integration tests, not for ordinary chat.

    ./configure
    make
    make check-offline
    make check
    make install PREFIX="$HOME/.local"

See INSTALL for dependency and build details, SECURITY.md for the security
model and limits, and the release validation report for platforms actually
tested. Native BSD execution is a separate validation step; portability
intent is not evidence of having tested every Unix-like operating system.
make check-offline runs the CLI/PTY suite without a network socket. The
broader make check suite also uses local loopback fake servers.

This is an application of ThatIAm.vip (www.thatiam.vip), designed by remfan1994.
Source is available under the included IALA (Insha-Allah License Agreement),
whose full text is in LICENSE.md. Linked libraries keep their own licenses;
see NOTICE. The implementation was written for this specification without
copying another IRC client's implementation or configuration language.

PROTOCOL REFERENCES

    https://www.rfc-editor.org/rfc/rfc2812
    https://modern.ircdocs.horse/
    https://ircv3.net/specs/extensions/capability-negotiation
    https://ircv3.net/specs/extensions/sasl-3.1
    https://www.irchelp.org/protocol/ctcpspec.html
    https://www.irchelp.org/protocol/dccspec.html

IRC syntax and interoperability requirements come from protocol documents.
The program's interface and scope follow the project's requirements.
