Script: soju.py

Soju bouncer integration.
Author: Simon Ser — Version: 0.5.0 — License: AGPL-3.0-or-later
For WeeChat ≥ 0.3.0.
Tags: irc, soju, bouncer, py2, py3
Added: 2021-06-12 — Updated: 2023-07-07

Download GitHub Repository

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# Copyright (c) 2021 Simon Ser <contact@emersion.fr>
#
# License: GNU Affero General Public License version 3
# https://www.gnu.org/licenses/agpl-3.0.en.html

import weechat
import datetime

weechat.register("soju", "soju", "0.5.0", "AGPL3", "soju bouncer integration", "", "")

BOUNCER_CAP = "soju.im/bouncer-networks"

weechat_version = int(weechat.info_get("version_number", "") or 0)

if weechat_version < 0x04000000:
    caps_option = weechat.config_get("irc.server_default.capabilities")
    caps = weechat.config_string(caps_option)
    if BOUNCER_CAP not in caps:
        if caps != "":
            caps += ","
        caps += BOUNCER_CAP
        weechat.config_option_set(caps_option, caps, 1)

main_server = None
added_networks = {}

def server_by_name(server_name):
    hdata = weechat.hdata_get("irc_server")
    server_list = weechat.hdata_get_list(hdata, "irc_servers")
    if weechat_version >= 0x03040000:
        return weechat.hdata_search(
            hdata,
            server_list,
            "${irc_server.name} == ${name}",
            {},
            {"name": server_name},
            {},
            1,
        )
    else:
        return weechat.hdata_search(
            hdata,
            server_list,
            "${irc_server.name} == " + server_name,
            1,
        )

def handle_isupport_end_msg(data, signal, signal_data):
    global main_server

    server_name = signal.split(",")[0]
    netid = weechat.info_get("irc_server_isupport_value", server_name + ",BOUNCER_NETID")

    if netid != "":
        added_networks[netid] = True

    server = server_by_name(server_name)

    hdata = weechat.hdata_get("irc_server")
    cap_list = weechat.hdata_hashtable(hdata, server, "cap_list")
    if not BOUNCER_CAP in cap_list:
        return weechat.WEECHAT_RC_OK

    if main_server is not None:
        return weechat.WEECHAT_RC_OK
    main_server = server_name

    weechat.command(weechat.buffer_search("irc", "server." + server_name), "/quote BOUNCER LISTNETWORKS")

    return weechat.WEECHAT_RC_OK

def handle_bouncer_msg(data, signal, signal_data):
    server_name = signal.split(",")[0]
    msg = weechat.info_get_hashtable("irc_message_parse", { "message": signal_data })

    args = msg["arguments"].split(" ")
    if args[0] != "NETWORK":
        return weechat.WEECHAT_RC_OK

    # Don't connect twice to the same network
    netid = args[1]
    if netid in added_networks:
        return weechat.WEECHAT_RC_OK_EAT

    # Retrieve the network name from the attributes
    net_name = None
    raw_attr_list = args[2].split(";")
    for raw_attr in raw_attr_list:
        k, v = raw_attr.split("=")
        if k == "name":
            net_name = v
            break

    check_char = lambda ch: ch.isalnum() or ch in ".-_"
    net_name = "".join(ch if check_char(ch) else "_" for ch in net_name)

    addr = weechat.config_string(weechat.config_get("irc.server." + server_name + ".addresses"))
    add_server = [
        "/server",
        "add",
        net_name,
        addr,
        "-temp",
    ]

    if weechat_version >= 0x04000000:
        add_server.append("-tls")
    else:
        add_server.append("-ssl")

    # User name settings need to be adapted for new networks
    for k in ["username", "sasl_username"]:
        v = weechat.config_string(weechat.config_get("irc.server." + server_name + "." + k))
        if not v:
            continue
        username = v.split("/", maxsplit=1)[0] + "/" + net_name
        add_server.append("-" + k + "=" + username)

    for k in ["password", "sasl_mechanism", "sasl_password"]:
        v = weechat.config_string(weechat.config_get("irc.server." + server_name + "." + k))
        add_server.append("-" + k + "=" + v)

    weechat.command(weechat.buffer_search("core", "weechat"), " ".join(add_server))
    weechat.command(weechat.buffer_search("core", "weechat"), "/connect " + net_name)

    return weechat.WEECHAT_RC_OK_EAT

def handle_cap_sync_req(data, modifier, modifier_data, requested):
    supported = modifier_data.split(",")[1].split(" ")
    if BOUNCER_CAP in supported:
        requested += " " + BOUNCER_CAP
    return requested

weechat.hook_signal("*,irc_raw_in_376", "handle_isupport_end_msg", "") # RPL_ENDOFMOTD
weechat.hook_signal("*,irc_raw_in_422", "handle_isupport_end_msg", "") # ERR_NOMOTD
weechat.hook_signal("*,irc_raw_in_bouncer", "handle_bouncer_msg", "")
if weechat_version >= 0x04000000:
    weechat.hook_modifier("irc_cap_sync_req", "handle_cap_sync_req", "")