From bd9a8570423f7ffbd768f79256af51895f37b34d Mon Sep 17 00:00:00 2001 From: James Lu Date: Sun, 6 Sep 2015 23:11:31 -0700 Subject: [PATCH] docs: add auto-generated InspIRCd protocol spec, and finish off most of writing-plugins.md --- docs/technical/README.md | 7 +- docs/technical/inspircd_protocol.html | 405 ++++++++++++++++++++++++++ docs/technical/pmodule-spec.md | 27 ++ docs/technical/writing-plugins.md | 31 +- 4 files changed, 464 insertions(+), 6 deletions(-) create mode 100644 docs/technical/inspircd_protocol.html create mode 100644 docs/technical/pmodule-spec.md diff --git a/docs/technical/README.md b/docs/technical/README.md index 55cea6f..bb99e53 100644 --- a/docs/technical/README.md +++ b/docs/technical/README.md @@ -3,6 +3,8 @@ Please note that as PyLink is still in its development phase, the API is subject to change. Any documentation here is provided for reference only. +It is also really incomplete (contributors welcome!) + ### Introduction PyLink is an a modular, plugin-based IRC PseudoService framework. It uses swappable protocol modules and a hook-based system for calling plugins, allowing them to function regardless of the IRCd used. @@ -12,7 +14,10 @@ PyLink is an a modular, plugin-based IRC PseudoService framework. It uses swappa ### Contents - [Writing plugins for PyLink](writing-plugins.md) -- [PyLink hooks reference](hooks-reference.md) - [PyLink protocol module specification](pmodule-spec.md) + +#### Future topics (not yet available) + +- [PyLink hooks reference](hooks-reference.md) - [Writing tests for PyLink modules](writing-tests.md) - [Using PyLink's utils module](using-utils.md) diff --git a/docs/technical/inspircd_protocol.html b/docs/technical/inspircd_protocol.html new file mode 100644 index 0000000..f783fa3 --- /dev/null +++ b/docs/technical/inspircd_protocol.html @@ -0,0 +1,405 @@ + +Python: module inspircd + + + + + +
 
+ 
inspircd
index
/home/gl/pylink/protocols/inspircd.py
+

+

+ + + + + +
 
+Modules
       
hashlib
+os
+re
+
socket
+ssl
+sys
+
threading
+time
+utils
+
world
+

+ + + + + +
 
+Classes
       
+
ts6_common.TS6BaseProtocol(classes.Protocol) +
+
+
InspIRCdProtocol +
+
+
+

+ + + + + +
 
+Class = class InspIRCdProtocol(ts6_common.TS6BaseProtocol)
    
Method resolution order:
+
InspIRCdProtocol
+
ts6_common.TS6BaseProtocol
+
classes.Protocol
+
builtins.object
+
+
+Methods defined here:
+
__init__(self, irc)
+ +
awayClient(self, source, text)
Sends an AWAY message from a PyLink client. <text> can be an empty string
+to unset AWAY status.
+ +
connect(self)
Initializes a connection to a server.
+ +
handle_away(self, numeric, command, args)
Handles incoming AWAY messages.
+ +
handle_encap(self, numeric, command, args)
Handles incoming encapsulated commands (ENCAP). Hook arguments
+returned by this should have a parse_as field, that sets the correct
+hook name for the message.

+For InspIRCd, the only ENCAP command we handle right now is KNOCK.
+ +
handle_endburst(self, numeric, command, args)
ENDBURST handler; sends a hook with empty contents.
+ +
handle_events(self, data)
Event handler for the InspIRCd protocol. This passes most commands to
+the various handle_ABCD() functions elsewhere in this module, but also
+handles commands sent in the initial server linking phase.
+ +
handle_fhost(self, numeric, command, args)
Handles FHOST, used for denoting hostname changes.
+ +
handle_fident(self, numeric, command, args)
Handles FIDENT, used for denoting ident changes.
+ +
handle_fjoin(self, servernumeric, command, args)
Handles incoming FJOIN commands (InspIRCd equivalent of JOIN/SJOIN).
+ +
handle_fmode(self, numeric, command, args)
Handles the FMODE command, used for channel mode changes.
+ +
handle_fname(self, numeric, command, args)
Handles FNAME, used for denoting real name/gecos changes.
+ +
handle_ftopic(self, numeric, command, args)
Handles incoming FTOPIC (sets topic on burst).
+ +
handle_idle(self, numeric, command, args)
Handles the IDLE command, sent between servers in remote WHOIS queries.
+ +
handle_invite(self, numeric, command, args)
Handles incoming INVITEs.
+ +
handle_opertype(self, numeric, command, args)
Handles incoming OPERTYPE, which is used to denote an oper up.

+This calls the internal hook PYLINK_CLIENT_OPERED, sets the internal
+opertype of the client, and assumes setting user mode +o on the caller.
+ +
handle_ping(self, source, command, args)
Handles incoming PING commands, so we don't time out.
+ +
handle_pong(self, source, command, args)
Handles incoming PONG commands. This is used to keep track of whether
+the uplink is alive by the Irc() internals - a server that fails to reply
+to our PINGs eventually times out and is disconnected.
+ +
handle_server(self, numeric, command, args)
Handles incoming SERVER commands (introduction of servers).
+ +
handle_uid(self, numeric, command, args)
Handles incoming UID commands (user introduction).
+ +
inviteClient(self, numeric, target, channel)
Sends an INVITE from a PyLink client..
+ +
joinClient(self, client, channel)
Joins an internal spawned client <client> to a channel.
+ +
killClient(self, numeric, target, reason)
<self.irc object> <client numeric> <target> <reason>

+Sends a kill to <target> from a PyLink PseudoClient.
+ +
killServer(self, numeric, target, reason)
<self.irc object> <server SID> <target> <reason>

+Sends a kill to <target> from a PyLink PseudoServer.
+ +
knockClient(self, numeric, target, text)
Sends a KNOCK from a PyLink client.
+ +
modeClient(self, numeric, target, modes, ts=None)
Sends modes from a PyLink client. <modes> should be
+a list of (mode, arg) tuples, i.e. the format of utils.parseModes() output.
+ +
modeServer(self, numeric, target, modes, ts=None)
Sends modes from a PyLink server. <list of modes> should be
+a list of (mode, arg) tuples, i.e. the format of utils.parseModes() output.
+ +
numericServer(self, source, numeric, text)
+ +
pingServer(self, source=None, target=None)
Sends a PING to a target server. Periodic PINGs are sent to our uplink
+automatically by the Irc() internals; plugins shouldn't have to use this.
+ +
sjoinServer(self, server, channel, users, ts=None)
Sends an SJOIN for a group of users to a channel.

+The sender should always be a Server ID (SID). TS is optional, and defaults
+to the one we've stored in the channel state if not given.
+<users> is a list of (prefix mode, UID) pairs:

+Example uses:
+    sjoinServer(self.irc, '100', '#test', [('', '100AAABBC'), ('qo', 100AAABBB'), ('h', '100AAADDD')])
+    sjoinServer(self.irc, self.irc.sid, '#test', [('o', self.irc.pseudoclient.uid)])
+ +
spawnClient(self, nick, ident='null', host='null', realhost=None, modes=set(), server=None, ip='0.0.0.0', realname=None, ts=None, opertype=None)
Spawns a client with nick <nick> on the given IRC connection.

+Note: No nick collision / valid nickname checks are done here; it is
+up to plugins to make sure they don't introduce anything invalid.
+ +
spawnServer(self, name, sid=None, uplink=None, desc=None)
Spawns a server off a PyLink server.
+ +
squitServer(self, source, target, text='No reason given')
SQUITs a PyLink server.
+ +
topicServer(self, numeric, target, text)
Sends a burst topic from a PyLink server. This is usally used on burst.
+ +
updateClient(self, numeric, field, text)
Updates the ident, host, or realname of a PyLink client.
+ +
+Methods inherited from ts6_common.TS6BaseProtocol:
+
handle_error(self, numeric, command, args)
Handles ERROR messages - these mean that our uplink has disconnected us!
+ +
handle_kick(self, source, command, args)
Handles incoming KICKs.
+ +
handle_kill(self, source, command, args)
Handles incoming KILLs.
+ +
handle_mode(self, numeric, command, args)
Handles incoming user mode changes. For channel mode changes,
+TMODE (TS6/charybdis) and FMODE (Inspself.ircd) are used instead.
+ +
handle_nick(self, numeric, command, args)
Handles incoming NICK changes.
+ +
handle_notice = handle_privmsg(self, source, command, args)
Handles incoming PRIVMSG/NOTICE.
+ +
handle_part(self, source, command, args)
Handles incoming PART commands.
+ +
handle_privmsg(self, source, command, args)
Handles incoming PRIVMSG/NOTICE.
+ +
handle_quit(self, numeric, command, args)
Handles incoming QUITs.
+ +
handle_save(self, numeric, command, args)
Handles incoming SAVE messages, used to handle nick collisions.
+ +
handle_squit(self, numeric, command, args)
Handles incoming SQUITs (netsplits).
+ +
handle_topic(self, numeric, command, args)
Handles incoming TOPIC changes from clients. For topic bursts,
+TB (TS6/charybdis) and FTOPIC (Inspself.ircd) are used instead.
+ +
kickClient(self, numeric, channel, target, reason=None)
Sends a kick from a PyLink client.
+ +
kickServer(self, numeric, channel, target, reason=None)
Sends a kick from a PyLink server.
+ +
messageClient(self, numeric, target, text)
Sends a PRIVMSG from a PyLink client.
+ +
nickClient(self, numeric, newnick)
Changes the nick of a PyLink client.
+ +
noticeClient(self, numeric, target, text)
Sends a NOTICE from a PyLink client.
+ +
parseArgs(self, args)
Parses a string of RFC1459-style arguments split into a list, where ":" may
+be used for multi-word arguments that last until the end of a line.
+ +
parseTS6Args(self, args)
Similar to parseArgs(), but stripping leading colons from the first argument
+of a line (usually the sender field).
+ +
partClient(self, client, channel, reason=None)
Sends a part from a PyLink client.
+ +
quitClient(self, numeric, reason)
Quits a PyLink client.
+ +
removeClient(self, numeric)
Internal function to remove a client from our internal state.
+ +
topicClient(self, numeric, target, text)
Sends a TOPIC change from a PyLink client.
+ +
+Data descriptors inherited from classes.Protocol:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + +
 
+class InspIRCdProtocol(ts6_common.TS6BaseProtocol)
    
Method resolution order:
+
InspIRCdProtocol
+
ts6_common.TS6BaseProtocol
+
classes.Protocol
+
builtins.object
+
+
+Methods defined here:
+
__init__(self, irc)
+ +
awayClient(self, source, text)
Sends an AWAY message from a PyLink client. <text> can be an empty string
+to unset AWAY status.
+ +
connect(self)
Initializes a connection to a server.
+ +
handle_away(self, numeric, command, args)
Handles incoming AWAY messages.
+ +
handle_encap(self, numeric, command, args)
Handles incoming encapsulated commands (ENCAP). Hook arguments
+returned by this should have a parse_as field, that sets the correct
+hook name for the message.

+For InspIRCd, the only ENCAP command we handle right now is KNOCK.
+ +
handle_endburst(self, numeric, command, args)
ENDBURST handler; sends a hook with empty contents.
+ +
handle_events(self, data)
Event handler for the InspIRCd protocol. This passes most commands to
+the various handle_ABCD() functions elsewhere in this module, but also
+handles commands sent in the initial server linking phase.
+ +
handle_fhost(self, numeric, command, args)
Handles FHOST, used for denoting hostname changes.
+ +
handle_fident(self, numeric, command, args)
Handles FIDENT, used for denoting ident changes.
+ +
handle_fjoin(self, servernumeric, command, args)
Handles incoming FJOIN commands (InspIRCd equivalent of JOIN/SJOIN).
+ +
handle_fmode(self, numeric, command, args)
Handles the FMODE command, used for channel mode changes.
+ +
handle_fname(self, numeric, command, args)
Handles FNAME, used for denoting real name/gecos changes.
+ +
handle_ftopic(self, numeric, command, args)
Handles incoming FTOPIC (sets topic on burst).
+ +
handle_idle(self, numeric, command, args)
Handles the IDLE command, sent between servers in remote WHOIS queries.
+ +
handle_invite(self, numeric, command, args)
Handles incoming INVITEs.
+ +
handle_opertype(self, numeric, command, args)
Handles incoming OPERTYPE, which is used to denote an oper up.

+This calls the internal hook PYLINK_CLIENT_OPERED, sets the internal
+opertype of the client, and assumes setting user mode +o on the caller.
+ +
handle_ping(self, source, command, args)
Handles incoming PING commands, so we don't time out.
+ +
handle_pong(self, source, command, args)
Handles incoming PONG commands. This is used to keep track of whether
+the uplink is alive by the Irc() internals - a server that fails to reply
+to our PINGs eventually times out and is disconnected.
+ +
handle_server(self, numeric, command, args)
Handles incoming SERVER commands (introduction of servers).
+ +
handle_uid(self, numeric, command, args)
Handles incoming UID commands (user introduction).
+ +
inviteClient(self, numeric, target, channel)
Sends an INVITE from a PyLink client..
+ +
joinClient(self, client, channel)
Joins an internal spawned client <client> to a channel.
+ +
killClient(self, numeric, target, reason)
<self.irc object> <client numeric> <target> <reason>

+Sends a kill to <target> from a PyLink PseudoClient.
+ +
killServer(self, numeric, target, reason)
<self.irc object> <server SID> <target> <reason>

+Sends a kill to <target> from a PyLink PseudoServer.
+ +
knockClient(self, numeric, target, text)
Sends a KNOCK from a PyLink client.
+ +
modeClient(self, numeric, target, modes, ts=None)
Sends modes from a PyLink client. <modes> should be
+a list of (mode, arg) tuples, i.e. the format of utils.parseModes() output.
+ +
modeServer(self, numeric, target, modes, ts=None)
Sends modes from a PyLink server. <list of modes> should be
+a list of (mode, arg) tuples, i.e. the format of utils.parseModes() output.
+ +
numericServer(self, source, numeric, text)
+ +
pingServer(self, source=None, target=None)
Sends a PING to a target server. Periodic PINGs are sent to our uplink
+automatically by the Irc() internals; plugins shouldn't have to use this.
+ +
sjoinServer(self, server, channel, users, ts=None)
Sends an SJOIN for a group of users to a channel.

+The sender should always be a Server ID (SID). TS is optional, and defaults
+to the one we've stored in the channel state if not given.
+<users> is a list of (prefix mode, UID) pairs:

+Example uses:
+    sjoinServer(self.irc, '100', '#test', [('', '100AAABBC'), ('qo', 100AAABBB'), ('h', '100AAADDD')])
+    sjoinServer(self.irc, self.irc.sid, '#test', [('o', self.irc.pseudoclient.uid)])
+ +
spawnClient(self, nick, ident='null', host='null', realhost=None, modes=set(), server=None, ip='0.0.0.0', realname=None, ts=None, opertype=None)
Spawns a client with nick <nick> on the given IRC connection.

+Note: No nick collision / valid nickname checks are done here; it is
+up to plugins to make sure they don't introduce anything invalid.
+ +
spawnServer(self, name, sid=None, uplink=None, desc=None)
Spawns a server off a PyLink server.
+ +
squitServer(self, source, target, text='No reason given')
SQUITs a PyLink server.
+ +
topicServer(self, numeric, target, text)
Sends a burst topic from a PyLink server. This is usally used on burst.
+ +
updateClient(self, numeric, field, text)
Updates the ident, host, or realname of a PyLink client.
+ +
+Methods inherited from ts6_common.TS6BaseProtocol:
+
handle_error(self, numeric, command, args)
Handles ERROR messages - these mean that our uplink has disconnected us!
+ +
handle_kick(self, source, command, args)
Handles incoming KICKs.
+ +
handle_kill(self, source, command, args)
Handles incoming KILLs.
+ +
handle_mode(self, numeric, command, args)
Handles incoming user mode changes. For channel mode changes,
+TMODE (TS6/charybdis) and FMODE (Inspself.ircd) are used instead.
+ +
handle_nick(self, numeric, command, args)
Handles incoming NICK changes.
+ +
handle_notice = handle_privmsg(self, source, command, args)
Handles incoming PRIVMSG/NOTICE.
+ +
handle_part(self, source, command, args)
Handles incoming PART commands.
+ +
handle_privmsg(self, source, command, args)
Handles incoming PRIVMSG/NOTICE.
+ +
handle_quit(self, numeric, command, args)
Handles incoming QUITs.
+ +
handle_save(self, numeric, command, args)
Handles incoming SAVE messages, used to handle nick collisions.
+ +
handle_squit(self, numeric, command, args)
Handles incoming SQUITs (netsplits).
+ +
handle_topic(self, numeric, command, args)
Handles incoming TOPIC changes from clients. For topic bursts,
+TB (TS6/charybdis) and FTOPIC (Inspself.ircd) are used instead.
+ +
kickClient(self, numeric, channel, target, reason=None)
Sends a kick from a PyLink client.
+ +
kickServer(self, numeric, channel, target, reason=None)
Sends a kick from a PyLink server.
+ +
messageClient(self, numeric, target, text)
Sends a PRIVMSG from a PyLink client.
+ +
nickClient(self, numeric, newnick)
Changes the nick of a PyLink client.
+ +
noticeClient(self, numeric, target, text)
Sends a NOTICE from a PyLink client.
+ +
parseArgs(self, args)
Parses a string of RFC1459-style arguments split into a list, where ":" may
+be used for multi-word arguments that last until the end of a line.
+ +
parseTS6Args(self, args)
Similar to parseArgs(), but stripping leading colons from the first argument
+of a line (usually the sender field).
+ +
partClient(self, client, channel, reason=None)
Sends a part from a PyLink client.
+ +
quitClient(self, numeric, reason)
Quits a PyLink client.
+ +
removeClient(self, numeric)
Internal function to remove a client from our internal state.
+ +
topicClient(self, numeric, target, text)
Sends a TOPIC change from a PyLink client.
+ +
+Data descriptors inherited from classes.Protocol:
+
__dict__
+
dictionary for instance variables (if defined)
+
+
__weakref__
+
list of weak references to the object (if defined)
+
+

+ + + + + +
 
+Data
       conf = {'bot': {'loglevel': 'CRITICAL', 'nick': 'PyLink', 'realname': 'PyLink Service Client', 'serverdesc': 'PyLink unit tests', 'user': 'pylink'}, 'servers': defaultdict(<function <lambda> at 0x7f47d93ddc80>, {})}
+curdir = 'protocols'
+log = <logging.RootLogger object>
+ \ No newline at end of file diff --git a/docs/technical/pmodule-spec.md b/docs/technical/pmodule-spec.md new file mode 100644 index 0000000..257c9f9 --- /dev/null +++ b/docs/technical/pmodule-spec.md @@ -0,0 +1,27 @@ +This page is still incomplete. See [inspircd_protocol.html](inspircd_protocol.html) for an auto-generated specification of the protocol module. Any camelCase `ABCServer/Client` functions are outgoing commands, and include the following: + +- `awayClient` +- `inviteClient` +- `joinClient` +- `kickClient` +- `kickServer` +- `killClient` +- `killServer` +- `knockClient` +- `messageClient` +- `modeClient` +- `modeServer` +- `nickClient` +- `noticeClient` +- `numericServer` +- `partClient` +- `pingServer` +- `quitClient` +- `removeClient` +- `sjoinServer` +- `spawnClient` +- `spawnServer` +- `squitServer` +- `topicClient` +- `topicServer` +- `updateClient` diff --git a/docs/technical/writing-plugins.md b/docs/technical/writing-plugins.md index e28cb22..46c349d 100644 --- a/docs/technical/writing-plugins.md +++ b/docs/technical/writing-plugins.md @@ -2,7 +2,7 @@ PyLink plugins are modules that extend its functionality by giving it something to do. Without any plugins loaded, PyLink can only sit on a server and do absolutely nothing. -This guide, along with the sample plugin [`plugin-example.py`](plugin-example.py), aim to show the basics of writing plugins for PyLink. +This guide, along with the sample plugin [`plugin_example.py`](plugin_example.py), aim to show the basics of writing plugins for PyLink. ### Receiving data from IRC @@ -28,7 +28,7 @@ Hook functions do not return anything, and can raise exceptions to be caught by ### PyLink commands -For plugins that interact with IRC users, there is also the option of binding to PM commands. +For plugins that interact with IRC users, there is also the option of binding to PM commands. Commands are bound to using the `utils.add_cmd()` function: `utils.add_cmd(testcommand, "hello")`. Here, `testcommand` is the name of your function, and `hello` is the (optional) name of the command to bind to; if it is not specified, it'll use the same name as the function. Now, your command function will be called whenever someone PMs the PyLink client with the command (e.g. `/msg PyLink hello`, case-insensitive). @@ -38,12 +38,33 @@ Each command function takes 3 arguments: `irc, source, args`. - **source**: The numeric of the sender. This will usually be a UID (for users) or a SID (for server). - **args**: A `list` of space-separated command args (excluding the command name) that the command was called with. For example, `/msg PyLink hello world 1234` would give an `args` list of `['world', '1234']` -Command handlers do not return anything, and can raise exceptions to be caught by the core. +Command handlers do not return anything and can raise exceptions, which are caught by the core and automatically return an error message. ### WHOIS handlers The third option, `WHOIS` handlers, are a lot more limited compared to the other options. They are solely used for `WHOIS` replies, **and only work on IRCds where WHOIS commands are sent to remote servers!** This includes Charybdis and UnrealIRCd, but **not** InspIRCd, which handles all `WHOIS` requests locally (the only thing sent between servers is an IDLE time query). -WHOIS replies are special in that any plugins wishing to add lines to a WHOIS reply must do so after the regular WHOIS lines (handled by the core), but before a special "End of WHOIS" line. This means that the regular hooks mechanism, which are only called after core handling, won't work here. +WHOIS replies are special in that any plugins wishing to add lines to a WHOIS reply must do so after the regular WHOIS lines (handled by the core), but before a special "End of WHOIS" line. This means that the regular hooks mechanism, which are only called after core handling, doesn't work here. -\- section under construction - +An example of a plugin WHOIS handler is in the relay plugin. WHOIS handler functions are added to the `world.whois_handlers` list using a simple `append()`. They should return either nothing or a two-length list: the first item being the WHOIS numeric, and the second the raw whois text. + +``` +def relayWhoisHandler(irc, target): + user = irc.users[target] + orig = getLocalUser(irc, target) + if orig: + network, remoteuid = orig + remotenick = world.networkobjects[network].users[remoteuid].nick + return [320, "%s :is a remote user connected via PyLink Relay. Home " + "network: %s; Home nick: %s" % (user.nick, network, + remotenick)] +world.whois_handlers.append(relayWhoisHandler) +``` + +### Sending data to IRC + +Plugins receive data from the underlying protocol module, and communicate back using outgoing [command functions](pmodule-spec.md) implemented by the protocol module. They should *never* send raw data directly back to IRC, because that wouldn't be portable across different IRCds. + +These functions are usually called in this fashion: `irc.proto.abcdClient(arg1, arg2)`. For example, the command `irc.proto.joinClient('10XAAAAAB', '#bots')` would join a PyLink client with UID `10XAAAAAB` to channel `#bots`. + +For sending messages (e.g. replies to commands), a simpler form of `irc.msg(targetUID, text, notice=False, source=None)` is also used. The sender UID can be set here with the `source` argument, and defaults to the main PyLink client.