Script: autojoin.py

Configure autojoin for all servers according to currently joined channels.
Author: xt — Version: 0.3.1 — License: GPL3
For WeeChat ≥ 0.3.0.
Tags: irc, autojoin, py2, py3
Added: 2009-06-18 — Updated: 2019-10-06

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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
# -*- coding: utf-8 -*-
#
# Copyright (c) 2009 by xt <xt@bash.no>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

# (this script requires WeeChat 0.3.0 or newer)
#
# History:
# 2009-06-18, xt <xt@bash.no>
#     version 0.1: initial release
#
# 2009-10-18, LBo <leon@tim-online.nl>
#     version 0.2: added autosaving of join channels
#     /set plugins.var.python.autojoin.autosave 'on'
#
# 2009-10-19, LBo <leon@tim-online.nl>
#     version 0.2.1: now only responds to part messages from self
#     find_channels() only returns join'ed channels, not all the buffers
#     updated description and docs
#
# 2009-10-20, LBo <leon@tim-online.nl>
#     version 0.2.2: fixed quit callback
#     removed the callbacks on part & join messages
#
# 2012-04-14, Filip H.F. "FiXato" Slagter <fixato+weechat+autojoin@gmail.com>
#     version 0.2.3: fixed bug with buffers of which short names were changed.
#                    Now using 'name' from irc_channel infolist.
#     version 0.2.4: Added support for key-protected channels
#
# 2014-05-22, Nathaniel Wesley Filardo <PADEBR2M2JIQN02N9OO5JM0CTN8K689P@cmx.ietfng.org>
#     version 0.2.5: Fix keyed channel support
#
# 2016-01-13, The fox in the shell <KellerFuchs@hashbang.sh>
#     version 0.2.6: Support keeping chan list as secured data
#
# 2018-08-09, Julien Palard <julien@palard.fr>
#     version 0.3.0: Support for Python 3
#
# 2019-09-28, fructose
#     version 0.3.1: Error on invalid arguments
#
# @TODO: add options to ignore certain buffers
# @TODO: maybe add an option to enable autosaving on part/join messages

import weechat as w
import re

SCRIPT_NAME    = "autojoin"
SCRIPT_AUTHOR  = "xt <xt@bash.no>"
SCRIPT_VERSION = "0.3.1"
SCRIPT_LICENSE = "GPL3"
SCRIPT_DESC    = "Configure autojoin for all servers according to currently joined channels"
SCRIPT_COMMAND = "autojoin"

# script options
settings = {
    "autosave": "off",
}

if w.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE, SCRIPT_DESC, "", ""):

    w.hook_command(SCRIPT_COMMAND,
                   SCRIPT_DESC,
                   "[--run]",
                   "   --run: actually run the commands instead of displaying\n",
                   "--run",
                   "autojoin_cb",
                   "")

    # w.hook_signal('*,irc_in2_join', 'autosave_channels_on_activity', '')
    # w.hook_signal('*,irc_in2_part', 'autosave_channels_on_activity', '')
    w.hook_signal('quit',           'autosave_channels_on_quit', '')

# Init everything
for option, default_value in settings.items():
    if w.config_get_plugin(option) == "":
        w.config_set_plugin(option, default_value)


def autosave_channels_on_quit(signal, callback, callback_data):
    ''' Autojoin current channels '''
    if w.config_get_plugin(option) != "on":
        return w.WEECHAT_RC_OK

    items = find_channels()

    # print/execute commands
    for server, channels in items.items():
        process_server(server, channels)

    return w.WEECHAT_RC_OK


def autosave_channels_on_activity(signal, callback, callback_data):
    ''' Autojoin current channels '''
    if w.config_get_plugin(option) != "on":
        return w.WEECHAT_RC_OK

    items = find_channels()

    # print/execute commands
    for server, channels in items.items():
        nick = w.info_get('irc_nick', server)

        pattern = "^:%s!.*(JOIN|PART) :?(#[^ ]*)( :.*$)?" % nick
        match = re.match(pattern, callback_data)

        if match:  # check if nick is my nick. In that case: save
            process_server(server, channels)
        else:  # someone else: ignore
            continue

    return w.WEECHAT_RC_OK


def autojoin_cb(data, buffer, args):
    if args == '--run':
        run = True
    elif args != '':
        w.prnt('', 'Unexpected argument: %s' % args)
        return w.WEECHAT_RC_ERROR
    else:
        run = False

    # Old behaviour: doesn't save empty channel list
    # In fact should also save open buffers with a /part'ed channel
    # But I can't believe somebody would want that behaviour
    items = find_channels()

    # print/execute commands
    for server, channels in items.items():
        process_server(server, channels, run)

    return w.WEECHAT_RC_OK


def process_server(server, channels, run=True):
    option = "irc.server.%s.autojoin" % server
    channels = channels.rstrip(',')
    oldchans = w.config_string(w.config_get(option))

    if not channels:  # empty channel list
        return

    # Note: re already caches the result of regexp compilation
    sec = re.match('^\${sec\.data\.(.*)}$', oldchans)
    if sec:
        secvar = sec.group(1)
        command = "/secure set %s %s" % (secvar, channels)
    else:
        command = "/set irc.server.%s.autojoin '%s'" % (server, channels)

    if run:
        w.command('', command)
    else:
        w.prnt('', command)


def find_channels():
    """Return list of servers and channels"""
    # TODO: make it return a dict with more options like "nicks_count etc."
    items = {}
    infolist = w.infolist_get('irc_server', '', '')
    # populate servers
    while w.infolist_next(infolist):
        items[w.infolist_string(infolist, 'name')] = ''

    w.infolist_free(infolist)

    # populate channels per server
    for server in items.keys():
        keys = []
        keyed_channels = []
        unkeyed_channels = []
        items[server] = ''  # init if connected but no channels
        infolist = w.infolist_get('irc_channel', '',  server)
        while w.infolist_next(infolist):
            if w.infolist_integer(infolist, 'nicks_count') == 0:
                # parted but still open in a buffer: bit hackish
                continue
            if w.infolist_integer(infolist, 'type') == 0:
                key = w.infolist_string(infolist, "key")
                if len(key) > 0:
                    keys.append(key)
                    keyed_channels.append(w.infolist_string(infolist, "name"))
                else:
                    unkeyed_channels.append(w.infolist_string(infolist, "name"))
        items[server] = ','.join(keyed_channels + unkeyed_channels)
        if len(keys) > 0:
            items[server] += ' %s' % ','.join(keys)
        w.infolist_free(infolist)

    return items