# PBot PBot is a pragmatic IRCv3 Bot written in Perl * [Installation / Quick Start](#installation--quick-start) * [Features](#features) * [IRCv3 capable](#ircv3-capable) * [Powerful command interpreter](#powerful-command-interpreter) * [Piping](#piping) * [Substitution](#substitution) * [Variables](#variables) * [Selectors](#selectors) * [Inline invocation](#inline-invocation) * [Chaining](#chaining) * [Background processing](#background-processing) * [Output customization](#output-customization) * [Newlines in messages](#newlines-in-messages) * [Truncating long messages](#truncating-long-messages) * [Extensible](#extensible) * [Factoids](#factoids) * [Code factoids](#code-factoids) * [Plugins](#plugins) * [Applets](#applets) * [Functions](#functions) * [Scripting interface](#scripting-interface) * [Virtual machine to safely execute user-submitted code](#virtual-machine-to-safely-execute-user-submitted-code) * [Powerful user management](#powerful-user-management) * [Useful IRC quality-of-life improvements](#useful-irc-quality-of-life-improvements) * [Channel management and protection](#channel-management-and-protection) * [Easy configuration](#easy-configuration) * [Live reloading of core modules or data files](#live-reloading-of-core-modules-or-data-files) * [Documentation](#documentation) * [Frequently Asked Questions](#frequently-asked-questions) * [Support](#support) * [License](#license) ## Installation / Quick Start To get up-and-running quickly, check out the [Quick Start guide](doc/QuickStart.md). ## Features ### IRCv3 capable PBot supports several features of the IRCv3 specification. * client capability negotiation * SASL authentication * account-tag, account-notify, extended-join, message-tags, and more. ### Powerful command interpreter PBot has a powerful command interpreter with useful functionality, and tons of built-in commands. For more information, see the [Commands documentation.](doc/Commands.md) #### Piping You can pipe output from one command as input into another command, indefinitely. !echo hello world | {sed s/world/everybody/} | {uc} HELLO EVERYBODY [Learn more.](doc/Commands.md#piping) #### Substitution You can insert the output from another command at any point within a command. This substitutes the command with its output at the point where the command was used. !echo This is &{echo a demonstration} of command substitution This is a demonstration of command substitution For example, suppose you want to make a Google Image Search command. The naive way would be to simply do: !factadd img /call echo https://google.com/search?tbm=isch&q=$args Unfortuately this would not support queries containing spaces or certain symbols. But never fear! We can use command substitution and the `uri_escape` function from the `func` command. Note that you must escape the command substitution to insert it literally into the factoid otherwise it will be expanded first. !factadd img /call echo https://google.com/search?tbm=isch&q=\&{func uri_escape $args} !img spaces & stuff https://google.com/search?tbm=isch&q=spaces%20%26%20stuff [Learn more.](doc/Commands.md#substitution) #### Variables You can use factoids as variables and interpolate them within commands. !factadd greeting "Hello, world" !echo greeting is $greeting greeting is Hello, world PBot variable interpolation supports [expansion modifiers](doc/Factoids.md#expansion-modifiers), which can be chained to combine their effects. !echo $greeting:uc HELLO, WORLD [Learn more.](doc/Factoids.md#list-variables) #### Selectors You can select a random item from a selection list and interpolate the value within commands. !echo This is a %(neat|cool|awesome) bot. This is a cool bot. [Learn more.](doc/Commands.md#selectors) #### Inline invocation You can invoke up to three commands inlined within a message. If the message is addressed to a nick, the output will also be addressed to them. newuser13: Check the !{version} and the !{help} documentation. newuser13: PBot version 2696 2020-01-04 newuser13: To learn all about me, see https://github.com/pragma-/pbot/tree/master/doc [Learn more.](doc/Commands.md#command-invocation) #### Chaining You can execute multiple commands sequentially as one command. !echo Test! ;;; me smiles. ;;; version Test! * PBot smiles. PBot version 2696 2020-01-04 [Learn more.](doc/Commands.md#chaining) #### Background processing Suppose you make a Plugin that provides a command that may potentially take a long time to complete? Not a problem! You can use the [`cmdset`](doc/Admin.md#cmdset) command to set the `background-process` [command metadata](doc/Admin.md#command-metadata-list) and the command will now run as a background process, allowing PBot to carry on with its duties. The familiar [`ps`](doc/Admin.md#ps) and [`kill`](doc/Admin.md#kill) commands can be used to list and kill the background processes. You can also [`cmdset`](doc/Admin.md#cmdset) the `process-timeout` [command metadata](doc/Admin.md#command-metadata-list) to set the timeout, in seconds, before the command is automatically killed. Otherwise the `processmanager.default_timeout` [registry value](doc/Registry.md) will be used. ### Output customization #### Newlines in messages By default, PBot replaces newlines in command output with spaces. This can be customized on a per-channel or global basis to instead preserve the newlines and output each line as a distinct message. [Learn more.](doc/FAQ.md#how-do-i-change-how-the-bot-outputs-multi-line-messages) #### Truncating long messages Output that is longer than the maximum length of an IRC message will be pasted, with all formatting preserved, to a web paste service. The IRC message itself will be truncated, with enough room to append the paste URL. When `preserve_newlines` is enabled, if there are more lines available than `max_newlines` then all of the lines will be pasted, with formatting preserved, to a web paste service. PBot will then output up to `max_newlines` lines as distinct messages and then output the URL to the paste. ### Extensible Additional commands and functionality can be added to PBot in the following ways. #### Factoids Factoids are a very special type of command. Anybody interacting with PBot can create, edit, delete and invoke factoids. A simple factoid merely displays the text the creator sets. !factadd hello /say Hello, $nick! hello added to global channel. PBot, hello Hello, pragma-! Significantly more complex factoids can be built by using `$variables`, command-substitution, command-piping, `/code` invocation, command prefixes such as `/say`, `/me`, `/msg`, and more! PBot factoids include these advanced features: * [undo/redo history](doc/Factoids.md#factundo) * [changelog history](doc/Factoids.md#factlog) * [channel namespaces](doc/Factoids.md#channel-namespaces) * [`factadd`](doc/Factoids.md#factadd) and [`factchange`](doc/Factoids.md#factchange) commands accept a `-url` option that sets the factoid contents from a paste website. In other words, you can edit a factoid's contents using your local editor, preserving line-breaks and indentation. * [advanced `$variable` interpolation](doc/Factoids.md#expansion-modifiers) (`$var:lc` to lowercase contents, `$var:ucfirst` to uppercase first letter, etc) * [factoid-based variable lists](doc/Factoids.md#list-variables) (e.g., add a factoid `colors` containing "red green blue" and then `!echo $colors` will randomly pick one) * [advanced argument processing](doc/Factoids.md#special-variables-1) (indexing, splicing, etc) * [metadata](doc/Factoids.md#factoid-metadata) (e.g. owner, times used, last used date, locked, etc) * [special commands](doc/Factoids.md#special-commands) (`/say`, `/me`, `/msg`, `/code`, etc) * and much, much more! For more information, see the [Factoids documentation](doc/Factoids.md). #### Code factoids Code factoids are a special type of factoid that executes its contents within a sandboxed virtual machine. The contents of code factoids must begin with the `/code` command: /code For example, the venerable `rot13` function: !factadd rot13 /code sh echo "$@" | tr a-zA-Z n-za-mN-ZA-M rot13 added to global channel. !rot13 Pretty neat, huh? Cerggl arng, uhu? Making a `choose` command: !factadd choose /code zsh _arr=($args); print $_arr[$((RANDOM % $#_arr + 1))] choose added to global channel. Using the `choose` command via an [inlined command](doc/Commands.md#inline-invocation): hmm, what should I have for dinner? !{choose chicken "roast beef" pizza meatloaf} pizza You can even pipe output from other commands to Code Factoids. !echo test | {rot13} grfg For more information, see the [Code Factoid documentation](doc/Factoids.md#code). #### Plugins PBot can dynamically load and unload Perl modules to alter its behavior. These are some of the plugins that PBot has; [there are many more](lib/PBot/Plugin): Plugin | Description --- | --- [ActionTrigger](lib/PBot/Plugin/ActionTrigger.pm) | Lets admins set regular expression triggers to execute PBot commands or factoids. [GoogleSearch](lib/PBot/Plugin/GoogleSearch.pm) | Performs Internet searches using the Google search engine. [Quotegrabs](lib/PBot/Plugin/Quotegrabs.pm) | Grabs channel messages as quotes for posterity. Can grab messages from anywhere in the channel history. Can grab multiple messages at once! [RemindMe](lib/PBot/Plugin/RemindMe.pm) | Lets people set up reminders. Lots of options. [Weather](lib/PBot/Plugin/Weather.pm) | Fetches and shows weather data for a location. [Wolfram](lib/PBot/Plugin/Wolfram.pm) | Queries Wolfram\|Alpha for answers. [Wttr](lib/PBot/Plugin/Wttr.pm) | Advanced weather Plugin with tons of options. Uses wttr.in. [UrlTitles](lib/PBot/Plugin/UrlTitles.pm) | When a URL is seen in a channel, intelligently display its title. It will not display titles that are textually similiar to the URL, in order to maintain the channel signal-noise ratio. There are even a few games! Plugin | Description --- | --- [Battleship](lib/PBot/Plugin/Battleship.pm) | The classic Battleship board game, simplified for IRC. Multiple players can compete at once on the same battlefield! [Connect4](lib/PBot/Plugin/Connect4.pm) | The classic two-player Connect-4 game. [Spinach](lib/PBot/Plugin/Spinach.pm) | An advanced multiplayer Trivia game engine with a twist! A question is shown. Everybody privately submits a false answer. All false answers and the true answer is shown. Everybody tries to guess the true answer. Points are gained when people pick your false answer! [Wordle](lib/PBot/Plugin/Wordle.pm) | Guess a word by submitting words for clues about which letters belong to the word. [WordMorph](lib/PBot/Plugin/WordMorph.pm) | Solve a path between two words by changing one letter at a time. #### Applets Applets are external command-line executable programs and scripts that can be loaded as PBot commands. Suppose you have the [Qalculate!](https://qalculate.github.io/) command-line program and you want to provide a PBot command for it. You can create a _very_ simple shell script containing: #!/bin/sh qalc "$*" And let's call it `qalc.sh` and put it in PBot's `applets/` directory. Then you can load it with the [`load`](doc/Admin.md#load) command. !load qalc qalc.sh Now you have a [Qalculate!](https://qalculate.github.io/) calculator in PBot! !qalc 2 * 2 2 * 2 = 4 These are just some of the applets PBot comes with; there are several more: Applet | Description --- | --- [C-to-English translator](applets/c2english) | Translates C code to natural English sentences. [C precedence analyzer](applets/paren) | Adds parentheses to C code to demonstrate precedence. [C Jeopardy! game](applets/cjeopardy) | C programming trivia game based on the Jeopardy! TV game show. [C Standard citations](applets/cstd.pl) | Cite specified sections/paragraphs from the C standard. [Virtual machine](applets/pbot-vm) | Executes arbitrary code and commands within a virtual machine. [dict.org Dictionary](applets/dict.org.pl) | Interface to dict.org for definitions, translations, acronyms, etc. [Urban Dictionary](applets/urban) | Search Urban Dictionary for definitions. [Manpages](applets/man.pl) | Display a concise formatting of manual pages (designed for C functions) For more information, see the [Applets documentation](doc/Applets.md). #### Functions Functions are commands that accept input, manipulate it and then output the result. They are extremely useful with [piping](#piping) or [command substituting](#substitution). For example, the `uri_escape` function demonstrated in the [Substitution](#substitution) section earlier makes text safe for use in a URL. uri_escape thing's & words thing%27s%20%26%20words We also saw the `sed` and `uc` functions demonstrated in [Piping](#piping). The `sed` function replaces text using a substitution regex. The `uc` function uppercases the text. echo Hello world! | {sed s/world/universe/} | {uc} HELLO UNIVERSE! Here's a short list of the Functions that come with PBot. Name | Description --- | --- `uri_escape` | Percent-encodes unsafe URI characters. `sed` | Performs sed-like regex substitution. `grep` | Searches a string, using a regex, and prints the matching whole-word (e.g. `echo pizza hamburger hotdog \| {grep burger}` outputs `hamburger`). `pluralize` | Intelligently makes a word or phrase plural. `unquote` | Removes surrounding quotation marks. `title` | Title-cases text. That is, lowercases the text then uppercases the first letter of each word. `ucfirst` | Uppercases the first character of the text. `uc` | Uppercases all characters. `lc` | Lowercases all characters. Additional Functions can easily be added by making a very simple PBot Plugin. For more information, see the [Functions documentation](doc/Functions.md). #### Scripting interface PBot uses [Plang](https://github.com/pragma-/Plang) as a scripting language. You can use the scripting language to construct advanced commands that are capable of interacting with PBot internal API functions. [Learn more.](doc/Plugins/Plang.md) ### Virtual machine to safely execute user-submitted code PBot can integrate with a virtual machine to safely execute arbitrary user-submitted operating system commands or code. PBot supports [several shells and languages](doc/Factoids.md#supported-languages) out of the box! One of PBot's most powerful features, [Code Factoids](#code-factoids), would not be possible without this. !sh echo Remember rot13? | tr a-zA-Z n-za-mN-ZA-M Erzrzore ebg13? !go package main\nimport "fmt"\nfunc main() { fmt.Print("foo" == "foo"); } true !python print('Hello there!') Hello there! PBot has extensive support for the C programming language. For instance, the C programming language plugin is integrated with the GNU Debugger. It will print useful debugging information. !cc char *p = 0; *p = 1; runtime error: store to null pointer of type 'char' Program received signal SIGSEGV, Segmentation fault at statement: *p = 1; It can display the value of the most recent statement if there is no program output. !cc sizeof (int) no output: sizeof(int) = 4 For more information about the C programming language plugin, see [the `cc` command in the Applets documentation.](doc/Applets.md#cc) For more information about the virtual machine, see the [Virtual Machine documentation.](doc/VirtualMachine.md) ### Powerful user management PBot has powerful yet simple user management functionality and commands. * instead of generic access-levels, PBot uses [fine-grained user capabilities](doc/Admin.md#user-capabilities), which can be grouped into roles such as Admin, ChanOp, Moderator, etc * user accounts can be global or channel-specific * users can be recognized by hostmask or required to login with password * users can adjust their [user-metadata](doc/Admin.md#user-metadata-list) with the [`my`](doc/Commands.md#my) command * and much, much more! For more information, see the [Admin documentation.](doc/Admin.md#user-management-commands) ### Useful IRC quality-of-life improvements * [`mode`](doc/Admin.md#mode) command can take wildcards, e.g. `mode +ov foo* bar*` to op nicks beginning with `foo` and voice nicks beginning with `bar` * `unban ` and `unmute ` will remove all bans/mutes matching their current or previously seen hostmasks or accounts * [`ban`](doc/Admin.md#banmute) and [`mute`](doc/Admin.md#banmute) will intelligently set banmasks; supports timeouts * [`ban`](doc/Admin.md#banmute) and [`mute`](doc/Admin.md#banmute) can take a comma-separate list of nicks. Will intelligently group them into multiple `MODE +bbbb` commands * [`kick`](doc/Admin.md#kick) can take a comma-separated list of nicks; also accepts wildcards * and much, much more! For more information, see the [Admin documentation.](doc/Admin.md) ### Channel management and protection PBot can perform the typical channel management tasks. * opping/deopping known users, etc * channel-mode tracking/protection * [user hostmask/alias tracking](doc/Admin.md#message-historyuser-tracking) * [ban-evasion detection](doc/Admin.md#akalink) * [flood detection](doc/AntiAbuse.md) * [silent join-flood enforcement](doc/AntiAbuse.md#setting-up-automatic-join-flood-enforcement) * whitelisting, blacklisting, etc * spam/advertisement detection * and much, much more! For more information, see the [Channels documentation](doc/Admin.md#channel-management-commands) and the [Anti-abuse documentation](doc/AntiAbuse.md) ### Easy configuration PBot's settings are contained in a central registry of key/value pairs grouped by sections. These settings can easily be configured via several methods: * [PBot's command-line arguments](doc/Registry.md#overriding-registry-values-via-command-line) * [simple built-in commands (`regset`, `regunset`, etc)](doc/Registry.md#registry-commands) * [editing](doc/Registry.md#editing-registry-file) the [`$data_dir/registry`](data/registry) plain-text JSON file For more information, see the [Registry documentation.](doc/Registry.md) ### Live reloading of core modules or data files Suppose you edit some PBot source file, be it a core file such as [PBot/Core/Interpreter.pm](lib/PBot/Core/Interpreter.pm) or a Plugin such as [PBot/Plugin/Wttr.pm](lib/PBot/Plugin/Wttr.pm). Or suppose there's a PBot update available. Most simple bots would require you to shut down the bot and restart it in order to see the modifications. Not PBot! you can simply use the [`refresh`](doc/Admin.md#refresh) command to reload all modified PBot core files and Plugins without bot restart. You can also use the [`reload`](doc/Admin.md#reload) command to reload any modified configuration or data files. ## Documentation See the [PBot documentation](doc) for more information. ## Frequently Asked Questions If you have a question, try the [PBot FAQ](doc/FAQ.md)! ## Support For additional questions and support, feel free to join the `#pbot` channel on the [Libera.Chat](https://libera.chat/guides) IRC network ([Web Chat](https://web.libera.chat/#pbot)). ## License PBot is licensed under the [MIT license](LICENSE).