Skip to content

API Python Events

frogged edited this page Feb 15, 2016 · 14 revisions

Introduction

This is part of the documentation of Verlihub's Python Plugin version 1.2.4.

A Python script can react to events happening in the hub and change their outcome. It is possible by the use of so-called hooks — top-level functions declared in the script that have names recognized by the Python plugin. All of them are called OnSomething (except one), where Something describes the type of event. For example, if a user enters the hub, the hub will ask the plugins to process the OnUserLogin event. When some user issues a command, it will trigger the OnUserCommand event.

Generally (exceptions will be discussed later), if a hook function returns nothing (None) or one (1), the hub will continue processing the event normally. However, if any of the scripts returns zero (0), it will be a sign to Verlihub to stop processing the event and abort the operation (if it can be blocked).

It is important to note that returning zero only blocks the handling of the event by other plugins and Verlihub itself. It will not block other Python scripts (or plugins that were called before Python) from noticing the event. All Python scripts are guaranteed to receive the event in the order that they appear in the output of the !pylist command.

OnUserCommand is a good example to show first. In the code below we implement our own version of the +myip command. If the command name matches, the script prints a main-chat message to the user with his IP and then returns zero to block further processing (because we don't want the user to see the IP information the hub normally prints when it receives this command). If the user writes a different command, the tested condition is not satisfied and the function returns the default value, None, which allows that command to be processed by other plugins and the hub.

import vh
def OnUserCommand(nick, command):
    if command[1:] == "myip":
        vh.usermc("Your IP is: %s" % vh.GetUserIP(nick), nick)
        return 0

Here return 0 blocks further processing by the hub. Had we wanted to exit the function without blocking the event, we would have written return without arguments (which returns the special value None).

When writing your own hook functions, make sure they can take in the expected number of required arguments. You can add optional arguments with specified default values if you wish, but if your definition cannot take all arguments from the caller or expects more, the function call will fail and an error will be reported in the logs. Look at OnUserCommand for example. It requires two arguments (nick and command). Let's see which definitions will be good and which will fail (function bodies not included):

def OnUserCommand(a, b):               # OK
def OnUserCommand(a, b, c=1):          # OK
def OnUserCommand(a="", b="", c=1):    # OK
def OnUserCommand(a, b="", c=1, d=2):  # OK
def OnUserCommand(a, b, **c):          # OK

def OnUserCommand(a):                  # WRONG: expects fewer arguments
def OnUserCommand(a, b, c):            # WRONG: expects more arguments

Also note that in the functions that contained parsed NMDC messages, the trailing pipe character is removed.

Special events

OnTimer, UnLoad, and OnUnLoad are three events that serve special purposes, instead of reporting that some user has performed some action, like all other events. They also ignore the return values. Other special events are OnScriptCommand and OnScriptQuery, because they were introduced to facilitate cooperation between scripts by the use of message passing. OnSetConfig can also be considered special — it's a way to tell plugins that a configuration variable is going to be changed and giving them the chance to prevent that.

OnTimer

Call: OnTimer(timestamp)

Arguments: timestamp (float; seconds since the epoch).

OnTimer is called by the hub roughly every second or every few seconds. The interval between the calls to OnTimer is specified in seconds by the timer_serv_period configuration variable, with default value being one second. The argument timestamp is the time in seconds that passed since the epoch (1970-01-01 00:00:00 UTC).

History: Originally OnTimer was called without arguments. Then, on 2015-09-27, in late version 1.2.0, the timestamp argument (int, showing milliseconds since the epoch) was added, breaking existing scripts and flooding hub logs with error messages about wrong number of arguments. If that wasn't bad enough, timestamp value was wrong on 32-bit systems, because the hub used only a 4-byte integer to store it (that made the value will go from −2147483648 to +2147483647 and then wrap around). Finally, on 2016-02-14, in version 1.2.4 this was fixed: timestamp is now a double-precision float showing the number of seconds since the epoch (with millisecond resolution), and you can also use the old OnTimer without arguments (first, the plugin will try to use OnTimer(timestamp), and if that fails, it will subsequently use OnTimer()).

If you want to achieve maximum backwards compatibility, it is wise to specify a default value for the timestamp argument (because it didn't exist before September 27, 2015) and not use it, but instead get the timestamp from Python's time module. This is the preferred way to handle the OnTimer event:

import vh, time
def OnTimer(tstamp=0):
    now = time.time()
    ... do something ...

If you want to know how much time has passed since the last call to OnTimer, that code becomes:

import vh, time
now = then = 0
def OnTimer(tstamp=0):
    global now, then
    now = time.time()
    info = "Time since last call: %s seconds" % (now - then)
    ... do something ...
    then = now

UnLoad

Call: UnLoad()

UnLoad is called before the script is removed from the plugin (by using the !pyunload or !pyreload commands, unloading the plugin, or closing the hub). Use it when you have to do some cleanup tasks before the script ends, for example: close network sockets, save configuration files, write statistics to the database, or say farewell to the users. It is also the right moment to remove a bot that was added previously by the script.

The following example is a complete script that adds a bot when it is loaded and removes the bot when it is unloaded. Thanks to the declaration and use of the script_online variable, you can even activate and deactivate the script without having to reload it (adding the necessary OnOperatorCommand function to do that is left to you).

import vh
script_online = False

def UnLoad():
    global script_online
    if script_online:
        script_online = False
        vh.DelRobot("SuperBOT")

def OnUnLoad(error_code):
    if not error_code:
        UnLoad()

def Init():
    global script_online
    if not script_online:
        vh.AddRobot("SuperBOT", 3, "I am a bot", "DSL", "[email protected]", 0)
        script_online = True

Init()

OnUnLoad

Call: OnUnLoad(error_code)

Arguments: error_code (int).

Added in late version 1.2.0 on 2015-09-27.

This function is called when the hub is shutting down (for example using the QUIT or SEGV signals, or commands like !restart or !quit). The error_code is normally zero, except the situation when the hub received a SEGV signal. Note that terminating the hub with the TERM and, obviously, KILL signals will not generate the OnUnLoad event.

After receiving this event you should perform necessary cleanup, but preferably only when error_code is zero, because you cannot trust the state of memory after a memory violation (SEGV signal). The UnLoad function is not called on hub termination, so you can put the cleanup code there and call UnLoad from OnUnLoad. Look at the example script in the description of UnLoad.

OnScriptCommand

Call: OnScriptCommand(command, data, plugin, script)

Arguments: command (str), data (str), plugin (str), script (str).

Added in version 1.2.3.

This event is generated when a script calls the ScriptCommand(command, data) callback function. Before it is sent to all the plugins, another two arguments are added: plugin — the name of the plugin where the caller script runs, for example "python" or "lua", and script — the full path to the caller script, for example "/home/mario/myhub/scripts/test.py". Return value is ignored; you cannot block further processing of this event.

Note that all plugins and all scripts receive the event, including the caller, so you should compare script against your vh.path.

Let's say that you have a script that blocks certain online users. You would like it to broadcast to other scripts that it has added someone to the blacklist and you would also like to give other scripts the ability to add nicks to the blacklist. You could do it like this:

import vh
blacklist = set()

def block(nick):
    if vh.GetUserClass(nick) not in [0, 1, 2]:
        return 0
    if nick in blacklist:
        return 2
    blacklist.add(nick)
    vh.ScriptCommand("blacklist_addition", nick)
    return 1

def OnScriptCommand(cmd, data, plug, script):
    if cmd == "add_to_blacklist":
        block(data)

def OnOperatorCommand(op, cmd):
    if cmd[1:10] == "blockuser":
        nick = cmd[11:]
        res = block(nick)
        if res == 1:
            vh.usermc("Added user %s to the blacklist" % nick, op)
        if res == 2:
            vh.usermc("User %s was already on the blacklist" % nick, op)
        else:
            vh.usermc("Could not add user %s to the blacklist" % nick, op)
        return 0

OnScriptQuery

Call: OnScriptQuery(command, data, plugin, script)

Arguments: command (str), data (str), plugin (str), script (str).

Added in version 1.2.4.

This function is seemingly similar to OnScriptCommand, but has two differences: it is generated by a call to ScriptQuery and you may return a string — it will be passed back to the script that called ScriptQuery. Using the example of the blacklist described earlier with OnScriptCommand, that makes life easier for the person who writes the script that interfaces with the blacklist script, because he can get immediate confirmation if the request was successful. For that purpose you would add the following function to the blacklist script:

def OnScriptQuery(cmd, data, plug, script):
    if cmd == "add_to_blacklist":
        return str(block(data))

The difference is that we now return a stringified result of the call to block(data). The script that called ScriptQuery will receive that string in the list that ScriptQuery returns and will be able to handle that response appropriately. That would be harder to do with ScriptCommand (caller would have to define a handler for the "blacklist_addition" script command and check if it registered the nick when the "add_to_blacklist" ScriptCommand he gave returns).

OnSetConfig

Call: OnSetConfig(nick, conf, var, val_new, val_old, val_type)

Arguments: nick (str), conf (str), var (str), val_new (str), val_old (str), val_type (int).

Added in version 1.2.4.

This event is triggered when a configuration variable var in file conf is about to be changed from val_old to val_new by an operator (then nick stores his name) or by a plugin (then nick == vh.botname). You can block this configuration change by returning 0.

val_type is the type of value the variable is represented inside the hub. Since version 1.2.5 you can compare val_type against the available types stored as vh module constants: vh.eIT_VOID (unspecified), vh.eIT_BOOL, vh.eIT_CHAR, vh.eIT_INT, vh.eIT_UINT (unsigned int), vh.eIT_LONG, vh.eIT_ULONG, vh.eIT_PCHAR (cstring), vh.eIT_TIMET, vh.eIT_LLONG (64-bit int), vh.eIT_ULLONG, vh.eIT_AR_BYTE (array of bytes), vh.eIT_STRING (std::string), vh.eIT_DOUBLE.

Commands and chat

OnUserCommand

Call: OnUserCommand(nick, command)

Arguments: nick (str), command (str).

This function is called when a user identified by nick writes a user command. If you recognize the command and handle it, you should return zero to block processing of this command by other plugins and the hub, which would end in the message "Unknown hub command" displayed to the user. However, if you only want to add to the output of an existing command or are writing a script that writes a log of all issued commands, you do not want to block further processing, so in that case do not return zero.

Command start with a special control character. It's good practice to ignore it and check if the string following that character is "something" rather than check if the whole command starts with "+something". You should not assume that + is the magical trigger. Therefore in the following example we check the substring command[1:] against "myip" instead of checking command against "+myip":

import vh
def OnUserCommand(nick, command):
    
    # Here we return 0, because we want to block the built-in +myip command.
    if command[1:] == "myip":
        vh.usermc("Your IP is: %s" % vh.GetUserIP(nick), nick)
        return 0
    
    # And here we pass all commands trough, registering them for specific users.
    if nick in ["Mario", "Luigi"]:
        vh.classmc("%s wrote command: %s" % (nick, command), 5, 10)
        return

Like it was said above, user commands are usually recognized by the prefix character +, but hub administrators can set other trigger characters with the config variable cmd_start_user. In the past it was only +, but in recent Verlihub builds it defaults to +!/ — these are the same characters as for operator commands. That creates a problem, because it changes behavior. In the old days, when an operator wrote a command starting with +, an OnUserCommand event was fired. Now, using default settings, the OnOperatorCommand event is triggered instead. It would make sense that any command issued by an operator is an OperatorCommand, but unfortunately that depends on hub settings. Scripts running on plugin version 1.2.4 and higher can use OnHubCommand to handle all commands in one place, like this:

import vh
def OnHubCommand(nick, command, uclass, in_pm, prefix):
    write = vh.pm if in_pm else vh.usermc
    
    if command == "info":
        if uclass > 2:
            write(get_all_hub_secrets(), nick)
        else:
            write(get_only_public_info(), nick)
        return 0
    
    if command == "myip":
        write("Your IP is: %s" % vh.GetUserIP(nick), nick)
        return 0

Scripts running on older plugin versions can instead use this command routing idea:

import vh
def OnOperatorCommand(nick, command):
    # Handle all privileged stuff reserved for operators:
    if command[1:] == "info":
        vh.usermc(get_all_hub_secrets(), nick)
        return 0

def OnUserCommand(nick, command):
    # First handle all commands common to operators and normal users:
    if command[1:] == "myip":
        vh.usermc("Your IP is: %s" % vh.GetUserIP(nick), nick)
        return 0
    
    if vh.GetUserClass(nick) > 2:
        return OnOperatorCommand(nick, command)
    
    # Now handle only commands for normal users:
    if command[1:] == "info":
        vh.usermc(get_only_public_info(), nick)
        return 0

OnOperatorCommand

Call: OnUserCommand(nick, command)

Arguments: nick (str), command (str).

This function is called when an operator (user with class 3 or above) identified by nick writes a command that starts with a trigger character listed in the config variable cmd_start_op (and if the trigger isn't listed there, an OnUserCommand event will be sent instead). Other than that, this command works exactly like OnUserCommand.

OnHubCommand

Call: OnHubCommand(nick, clean_command, user_class, in_pm, prefix)

Arguments: nick (str), clean_command (str), user_class (int), in_pm (int; 0 or 1), prefix (str; one character).

Added in version 1.2.4.

OnHubCommand is called after OnOperatorCommand or OnUserCommand, so it can be blocked if any script returns 0 in those event handlers. What are the benefits of using OnHubCommand instead of the two other commands? Here they are:

  • Those two events are combined into one and you only have to check the user_class argument to get the class of the user;
  • clean_command has the first character removed, so you do not have to skip over it or bother deciding if it's + or !;
  • and if for some reason you need to know the trigger character (like when you show the user how to use the command and are wondering: start it with + or ! ...), it is stored in the prefix argument;
  • in_pm gives you context information, so you know if to respond using vh.pm (when in_pm equals 1) or vh.usermc (when in_pm equals 0);
  • it's more versatile — it gives you class number instead of dividing into op commands and everything else;
  • and it's more maintainable — you don't have to keep around two event handlers.

Example use:

import vh
def OnHubCommand(nick, command, uclass, in_pm, prefix):
    write = vh.pm if in_pm else vh.usermc
    
    if command == "myip":
        write("Your IP is: %s" % vh.GetUserIP(nick), nick)
        return 0
    
    if uclass > 2:
        if command[:5] == "close":
            user = command[6:]
            if vh.GetUserClass(nick) < uclass:
                vh.CloseConnection(nick)
                write("User %s dropped." % user, nick)
            else:
                write("Cannot drop %s." % user, nick)
            return 0
        
        if command == "help close":
            info = "%sclose <nick> --- " % prefix
            info += "Disconnects a user of a class lower than yours."
            write(info, nick)
            return 0

OnParsedMsgChat

Call: OnParsedMsgChat(nick, msg)

Arguments: nick (str), msg (str).

Return: 0 — block; (nick, message) — substitute the message; 1 or None — continue processing.

This event is triggered when user nick writes a message msg in main chat. As usual, you can block the message by returning zero from this function, but additionally you can change it's contents (or the nick) by returning a tuple with two strings: new nick and new message — other scripts and plugins processing OnParsedMsgChat, and eventually the hub, will receive and process the altered message.

Here is an example utilizing both blocking and substitution:

import vh, string, re
leet_users = []

leet_repl = string.maketrans(\
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", \
"@8cd3fgh1jk1mn0pqr5+uvwxy2@8cd3fgh1jk1mn0pqR5+Uvwxy2")

def leet(s):
    return s.translate(leet_repl)

re_banned = re.compile(r"\b(dat ass|bromance|petextrian)\b", re.I)

def OnParsedMsgChat(nick, msg):
    if nick in leet_users:
        return nick, leet(data)
    
    if re_banned.search(data):
        vh.usermc("Message blocked. Learn to speak normally.", nick)
        return 0

OnParsedMsgPM

Call: OnParsedMsgPM(nick, msg, to_nick)

Arguments: nick (str), msg (str), to_nick (str).

User nick was about to send the private message msg to user to_nick. You can block the message by returning zero.

OnParsedMsgMCTo

Call: OnParsedMsgMCTo(nick, msg, to_nick)

Arguments: nick (str), msg (str), to_nick (str).

User nick was about to send the private mainchat message msg to user to_nick. You can block the message by returning zero.

OnOpChatMessage

Call: OnOpChatMessage(nick, msg)

Arguments: nick (str), msg (str).

Function is called when an operator identified by nick tries to send a message msg to operator chat (vh.opchatname). You can block the message by returning zero.

OnPublicBotMessage

Call: OnPublicBotMessage(nick, msg, min_class, max_class)

Arguments: nick (str), msg (str), min_class (int), max_class (int).

Barely ever used, so it's irrelevant.

Kicks and bans

OnOperatorKicks

Call: OnOperatorKicks(op, nick, reason)

Arguments: op (str), nick (str), reason (str).

This function is called when an operator op kicks the user nick, providing a specified reason. You can block the kick by returning zero from this function.

OnOperatorDrops

Call: OnOperatorDrops(op, nick)

Arguments: op (str), nick (str).

This function is called when an operator op drops a user nick using the !drop command. To prevent the user from being dropped return zero, for example:

import vh
def OnOperatorDrops(op, nick):
    if nick == 'Mario':
        vh.usermc("%s is under my protection!" % nick, op)
        return 0

OnOperatorDropsWithReason

Call: OnOperatorDropsWithReason(op, nick, reason)

Arguments: op (str), nick (str), reason (str).

Added in version 1.2.2

Since February 2016 an operator can send a message to the user he drops using the command !drop nick reason and plugins also receive the reason string. To prevent older Python scripts from breaking, OnOperatorDrops was preserved in the original form, with two arguments, but a new event handler was added instead, OnOperatorDropsWithReason, with the extra third argument, reason. When an operator drops someone (using either !drop nick or !drop nick reason), both functions will always be called — first the old one, then the new one. If the operator drops without giving a reason, reason will be an empty string.

Replace OnOperatorDrops with OnOperatorDropsWithReason in your scripts, if you care about why someone was dropped and have checked that the Python plugin's version is at least 1.2.2. If not, you can keep using OnOperatorDrops like before.

OnNewBan

Call: OnNewBan(op, ip, nick, reason)

Arguments: op (str), ip (str), nick (str), reason (str).

This event is triggered when an operator op is trying to ban user nick with goven ip, providing a specified reason. You can prevent the ban by returning zero.

User connection

OnNewConn

Call: OnNewConn(ip)

Arguments: ip (str).

This function is called at the first stage of the client's connection process. The client will be disconnected if you return zero.

import vh
banned_ips = set()
def OnNewConn(ip):
    if ip in banned_ips:
        vh.classmc("Blocked incoming connection from %s" % ip, 3, 10)
        return 0

OnCloseConn

Call: OnCloseConn(ip)

Arguments: ip (str).

This function is called when a client's connection to the hub is closed.

OnCloseConnEx

Call: OnCloseConnEx(ip, close_reason, nick)

Arguments: ip (str), close_reason (int), nick (str).

Added in version 1.2.4.

Can be used instead of OnCloseConn because it gives more valuable information by including the reason why the connection was closed (close_reason) and user's nick. If the connection was closed before login, nick will be an empty string. The close_reason is an integer that can be compared against the following vh module constants to get the actual reason for closing the connection:

vh.eCR_DEFAULT       # means not closed or unknown reason
vh.eCR_INVALID_USER  # bad nick, banned nick, ip or whatever
vh.eCR_KICKED        # user was kicked
vh.eCR_FORCEMOVE     # operator redirect command
vh.eCR_QUIT          # user quits himself
vh.eCR_HUB_LOAD      # critical hub load, no new users accepted
vh.eCR_TIMEOUT       # some kind of timeout
vh.eCR_TO_ANYACTION  # user did nothing for too long time
vh.eCR_USERLIMIT     # user limit exceeded for this user
vh.eCR_SHARE_LIMIT   # min or max share limit
vh.eCR_TAG_NONE      # no tags in description, or badly parsed
vh.eCR_TAG_INVALID   # tags not validated, slots, hubs etc.
vh.eCR_PASSWORD      # wrong password
vh.eCR_LOGIN_ERR     # error in login sequence
vh.eCR_SYNTAX        # syntax error in some message
vh.eCR_INVALID_KEY   # lock2key is invalid
vh.eCR_RECONNECT     # too fast reconnect
vh.eCR_CLONE         # clone detected
vh.eCR_SELF          # same user connects twice
vh.eCR_BADNICK       # bad nick, already used, too short etc.
vh.eCR_NOREDIR       # do not redirect, special reason

For example, you could log failed authentication like this:

import vh
def OnCloseConnEx(ip, reason, nick):
    if reason == vh.eCR_PASSWORD:
        vh.SendToOpChat("Failed login attempt as %s from %s" % (nick, ip))

OnUserLogin

Call: OnUserLogin(nick)

Arguments: nick (str).

This function is called when the user initiates the connection, successfully validates his nick and receives hub and user info. It has nothing to do with being a registered user — the event is triggered by any kind of user. If you return zero, the user will be disconnected.

import vh
def OnUserLogin(nick):
    vh.mc("Welcome, %s!" % nick)
    return

OnUserLogout

Call: OnUserLogout(nick)

Arguments: nick (str).

This function is called after a user disconnects. Naturally, you cannot block that event.

OnNewReg

Call: OnNewReg(op, nick, uclass)

Arguments: op (str), nick (str), uclass (int).

Called when operator op is registering user nick with class uclass. If you return zero, the registration process will be aborted.

OnValidateTag

Call: OnValidateTag(nick, data)

Arguments: nick (str), data (str).

You can use it to reject a user with a bad tag (to do that return zero). data holds the tag itself, for example: "<++ V:0.761,M:A,H:16/0/1,S:17>".

OnParsedMsgValidateNick

Call: OnParsedMsgValidateNick(data)

Arguments: data (str).

When the client connects to the hub it will try to verify that it can use a nick by sending a message data which looks like: "$ValidateNick Mario". The hub sends OnParsedMsgValidateNick event to the plugins and this is your chance to reject a nick that is inappropriate — if you return zero from this function, the client will be disconnected.

Other protocol messages

OnParsedMsgSearch

Call: OnParsedMsgSearch(nick, data)

Arguments: nick (str), data (str).

Event triggered when user nick tries to perform search. data is something like: "$Search ip:port F?T?0?9?TTH:hash" (replace ip, port, and hash with actual values). You can block this search by returning zero.

OnParsedMsgSR

Call: OnParsedMsgSR(nick, data)

Arguments: nick (str), data (str).

Function called when nick sends a search result data to user other_nick. data has the form: "$SR nick path_and_bytes free/slotsTTH:tth (ip:port)other_nick". Note that the hub receives this message only when other_nick is passive (and then you can block is by returning zero from this event handler). Active users receive search results directly from other people.

OnParsedMsgMyINFO

Call: OnParsedMsgMyINFO(nick, desc, tag, speed, mail, sharesize)

Arguments: nick (str), desc (str), tag (str), speed (str), mail (str), sharesize (str).

Return: 0 — block; tuple — substitute the MyINFO; 1 or None — continue processing.

Function is called when user nick sends a MyINFO message. The message has been split into chunks for easier handling. You can block the user from changing his MyINFO by returning zero. You also have a possibility to alter his MyINFO by returning a tuple with five elements: (desc, tag, speed, mail, sharesize). Those elements are strings that will replace parts of MyINFO. If any of the five elements has the value None, that part of MyINFO will remain unchanged.

OnFirstMyINFO

Call: OnFirstMyINFO(nick, desc, tag, speed, mail, sharesize)

Arguments: nick (str), desc (str), tag (str), speed (str), mail (str), sharesize (str).

Return: 0 — disconnect user; tuple — substitute the MyINFO; 1 or None — continue processing.

This is called when user nick sends MyINFO for the first time. It works exactly like OnParsedMsgMyINFO, except that when you return zero the user will be kicked from the hub.

OnParsedMsgAny

Call: OnParsedMsgAny(nick, data)

Arguments: nick (str), data (str).

This function is called for every message coming from a client if the nick is known (so not at the initial connecting stage, but for everything else).

OnParsedMsgAnyEx

Call: OnParsedMsgAnyEx(ip, data)

Arguments: ip (str), data (str).

This function is called for every message coming from a client at the initial stage, when the nick isn't yet known.

OnCtmToHub

Call: OnCtmToHub(nick, ip, port, server_port, referrer)

Arguments: nick (str), ip (str), port (int), server_port (int), referrer (str).

No idea what it does; never seen it being used.

OnParsedMsgSupports

Call: OnParsedMsgSupports(ip, data, filtered)

Arguments: ip (str), data (str), filtered (str).

Changed in version 1.2.1 on 2015-12-01. Before that, it was called OnParsedMsgSupport, did not have the third argument and was useless, because it did not store the IP address in the first argument.

Supports message is used to negotiate protocol extensions by indicating what extended features a DC client possesses. The first argument is the ip of the connected client, data is the original supports string sent by that client, which may look like this: "$Supports BotINFO ChatOnly NoGetINFO NoHello", and filtered is the list of supported features (without the $Supports string) that has been filtered but the hub and other plugins, so it could look for example like this: "HubINFO NoGetINFO NoHello ".

OnParsedMsgMyHubURL

Call: OnParsedMsgMyHubURL(nick, data)

Arguments: nick (str), data (str).

No idea what this is exactly. It's probably sent only by the pingers to let the hub know how they reached it. data is something like this: "$MyHubURL dchub://example.com:1234".

OnParsedMsgExtJSON

Call: OnParsedMsgExtJSON(nick, data)

Arguments: nick (str), data (str).

No idea what this is and haven't seen anyone use it.

OnParsedMsgBotINFO

Call: OnParsedMsgBotINFO(nick, data)

Arguments: nick (str), data (str).

Sent by pingers. data is something like: "$BotINFO The Super Pinger, www.example.com".

OnParsedMsgVersion

Call: OnParsedMsgVersion(ip, data)

Arguments: ip (str), data (str).

The NMDC protocol version sent during handshake. Currently data is: "$Version 1,0091".

OnParsedMsgMyPass

Call: OnParsedMsgMyPass(nick, data)

Arguments: nick (str), data (str).

Sent when user nick tries to log in. data is something like: "$MyPass password". You can use this function to register login attempts and detect attacks. Returning zero will instantly close the connection to the user.

OnParsedMsgConnectToMe

Call: OnParsedMsgConnectToMe(nick, other_nick, ip, port)

Arguments: nick (str), other_nick (str), ip (str), port (str).

Sent by user nick when he wants user other_nick to connect to him on given port and ip. Returning zero blocks the message.

OnParsedMsgRevConnectToMe

Call: OnParsedMsgRevConnectToMe(nick, other_nick)

Arguments: nick (str), other_nick (str).

Sent by a passive user nick when he wants to connect with user other_nick. If other_nick is active and willing, he will respond with a OnParsedMsgConnectToMe message. Returning zero blocks the message.

OnUnknownMsg

Call: OnUnknownMsg(nick, data)

Arguments: nick (str), data (str).

Every message that isn't part of NMDC protocol. Otherwise OnParsedMsgAny would have been used instead.

Clone this wiki locally