Clone

git clone git@git.secluded.site:xmppc.git

README

xmppc

xmppc is a CLI XMPP client written in C on top of libstrophe. It's useful when you want a script, shell, or agent to do one XMPP thing and then exit, like list a roster, send a chat message, read recent archive entries, wait for a reply, inspect bookmarks, and so on.

This repository is a fork β€” probably a hard fork β€” of the original xmppc. It may be renamed later. Please do not send issues from using this fork straight upstream; see Issues.

Install from source

On Debian or Ubuntu-like systems, install the build tools and libraries first:

sudo apt-get update
sudo apt-get install -y \
  autoconf \
  automake \
  gcc \
  libglib2.0-dev \
  libgpgme-dev \
  libstrophe-dev \
  libtool \
  make \
  pkg-config

Then build the binary:

./bootstrap.sh
./configure
make

Put the resulting xmppc somewhere in your PATH, for example:

mkdir -p ~/.local/bin
mv xmppc ~/.local/bin/xmppc

Files

  • ~/.config/xmppc/config β€” account configuration.
  • ~/.config/xmppc/AGENTS.md β€” optional instructions for LLM agents using xmppc.

Accounts and passwords

You can pass a JID directly:

xmppc --jid user@example.net --pwd 'secret' --mode roster list

If --pwd is omitted, xmppc asks for the password without echoing it. If you want to pipe a password in, use --pwd -:

pass show xmpp/example | xmppc --jid user@example.net --pwd - --mode roster list

Named accounts are probably nicer. xmppc reads them from ~/.config/xmppc/config; the [default] account is used when neither --account nor --jid is provided.

[default]
jid=user@example.net
pwd=secret

[work]
jid=user@work.example
pwd-cmd=pass show xmpp/work

[bot]
jid=bot@example.net
pwd=another-secret

Prefer pwd-cmd if you already keep passwords in a local password manager. It runs locally and its stdout, minus the trailing newline, becomes the password.

Command shape

Most commands follow this pattern:

xmppc [--account ACCOUNT] [--jid JID] [--pwd PASSWORD] --mode MODE COMMAND [args...]

Short options are available too:

xmppc -a work -m roster list
xmppc -j user@example.net -p - -m mam list friend@example.net

Use -v, -vv, -vvv, or -vvvv for progressively noisier logging. Use --help for the built-in summary.

Modes

Roster

xmppc -a work -m roster list
xmppc -a work -m roster export

list shows the account's contacts. export exports them.

Message

xmppc -a work -m message chat friend@example.net 'hello from xmppc'

message chat sends an unencrypted chat message. After the sent stanza appears in Message Archive Management (MAM), it prints one compact XML line:

<sent archive-id="mam-id" message-id="stanza-id" to="friend@example.net"/>

An important bit is the distinction between the two IDs:

  • archive-id is the MAM cursor. Use it with mam receive after-id=... when you want to wait for the next reply.
  • message-id is the client stanza ID. It's useful for matching messages, but it's not a MAM cursor.

If archive-id is empty, the message was sent but the archive cursor wasn't resolved before the lookup timed out. See Send, then wait for a reply for the fallback.

Message Archive Management (MAM)

MAM commands use XEP-0313 to read archived messages.

xmppc -a work -m mam list friend@example.net
xmppc -a work -m mam list with=friend@example.net start=-15m max=20
xmppc -a work -m mam receive friend@example.net after-id=mam-id timeout=300s max=5

mam list accepts unordered field=value terms:

  • with=<jid> filters to a conversation. A bare JID is shorthand for with=<jid>.
  • start=<time> and end=<time> bound the query. They accept XMPP timestamps or relative values such as -30s, -5m, -2h, or -1d.
  • after-id=<mam-id> and before-id=<mam-id> use RSM cursors.
  • ids=<id>[,<id>...] asks for specific archive IDs.
  • max=<n> limits the number of printed messages. It defaults to 5 and is capped at 50.

If you don't supply any range or ID field, mam list defaults to start=-5m so it doesn't accidentally ask for an unbounded archive.

mam receive is for β€œwait until someone replies.” It requires a conversation JID and after-id=<mam-id>, polls with real MAM/RSM after queries, and exits when at least one newer archived message is available or the timeout is reached. timeout defaults to 300s; max defaults to 5. If nothing arrives before the timeout, it exits without printing anything.

Normal MAM output is one XML record per archived message:

<message id="mam-id" message-id="stanza-id" stamp="..." from="..." to="..."><body>escaped body</body></message>

Again, id is the MAM archive cursor. message-id is the stanza ID.

There is also a nicer pretty command:

xmppc -a work -m mam pretty friend@example.net start=-5m

Send, then wait for a reply

  1. Send the message and capture the <sent .../> line.
  2. Extract archive-id.
  3. Run mam receive for the same JID with after-id=<archive-id>.

For example:

xmppc -a work -m message chat friend@example.net 'ping'
# extract archive-id from the sent line
xmppc -a work -m mam receive friend@example.net after-id='the-archive-id-from-sent'

That skips your outgoing message and waits only for newer archived messages in the conversation.

If the sent line has an empty archive-id, fall back to a recent mam list, find the message whose message-id matches the sent message-id, then use that message line's id as the after-id cursor.

PGP and OpenPGP

xmppc -a work -m pgp chat friend@example.net 'encrypted with old-style XEP-0027 PGP'
xmppc -a work -m openpgp signcrypt friend@example.net 'signed and encrypted with XEP-0373 OpenPGP'

The pgp mode supports XEP-0027. The openpgp mode supports XEP-0373 signcrypt.

OMEMO

xmppc -a work -m omemo list
xmppc -a work -m omemo delete-device-list

list shows OMEMO device IDs and fingerprints. delete-device-list removes the account's OMEMO device list.

Monitor

xmppc -a work -m monitor stanza
xmppc -a work -m monitor monitor

stanza monitors raw stanzas. monitor watches XEP-0277 microblog events.

Bookmarks

xmppc -a work -m bookmark list

Lists XEP-0048 bookmarks.

Discovery

xmppc -a work -m discovery info conference.example.net
xmppc -a work -m discovery item conference.example.net

Runs XEP-0030 service discovery info or item queries.

Agent support

This fork has an agent-skill command for LLM agents:

xmppc agent-skill

It prints an agent skill they should follow, the MAM cursor rules, and explains that agents should read ~/.config/xmppc/AGENTS.md when it exists for user-local instructions, but must not read ~/.config/xmppc/config.

To install a proper agent skill that points back to the one embedded in your binary, run:

xmppc agent-skill install

That writes:

  • ~/.agents/skills/communicating-through-xmppc/SKILL.md
  • ~/.agents/skills/communicating-through-xmppc/references/installation.md

Exit status

  • 0 means success.
  • 1 means failure.

Issues

Please don't report problems related to this fork to upstream xmppc! Send me a message somewhere (it's pretty easy to find how) and I'll decide whether it's a bug in my fork or something I should report upstream. Please don't bother the original maintainer with issues I may have introduced.

License

Copyright Β© 2020 Anoxinon e.V. This project is free software under the GNU General Public License. See LICENSE for the full text.