diff options
Diffstat (limited to 'ansible_collections/community/general/plugins/modules/irc.py')
-rw-r--r-- | ansible_collections/community/general/plugins/modules/irc.py | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/ansible_collections/community/general/plugins/modules/irc.py b/ansible_collections/community/general/plugins/modules/irc.py new file mode 100644 index 000000000..6cd7bc120 --- /dev/null +++ b/ansible_collections/community/general/plugins/modules/irc.py @@ -0,0 +1,311 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (c) 2013, Jan-Piet Mens <jpmens () gmail.com> +# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt) +# SPDX-License-Identifier: GPL-3.0-or-later + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + + +DOCUMENTATION = ''' +--- +module: irc +short_description: Send a message to an IRC channel or a nick +description: + - Send a message to an IRC channel or a nick. This is a very simplistic implementation. +extends_documentation_fragment: + - community.general.attributes +attributes: + check_mode: + support: full + diff_mode: + support: none +options: + server: + type: str + description: + - IRC server name/address + default: localhost + port: + type: int + description: + - IRC server port number + default: 6667 + nick: + type: str + description: + - Nickname to send the message from. May be shortened, depending on server's NICKLEN setting. + default: ansible + msg: + type: str + description: + - The message body. + required: true + topic: + type: str + description: + - Set the channel topic + color: + type: str + description: + - Text color for the message. ("none" is a valid option in 1.6 or later, in 1.6 and prior, the default color is black, not "none"). + Added 11 more colors in version 2.0. + default: "none" + choices: [ "none", "white", "black", "blue", "green", "red", "brown", "purple", "orange", "yellow", "light_green", "teal", "light_cyan", + "light_blue", "pink", "gray", "light_gray"] + aliases: [colour] + channel: + type: str + description: + - Channel name. One of nick_to or channel needs to be set. When both are set, the message will be sent to both of them. + nick_to: + type: list + elements: str + description: + - A list of nicknames to send the message to. One of nick_to or channel needs to be set. When both are defined, the message will be sent to both of them. + key: + type: str + description: + - Channel key + passwd: + type: str + description: + - Server password + timeout: + type: int + description: + - Timeout to use while waiting for successful registration and join + messages, this is to prevent an endless loop + default: 30 + use_ssl: + description: + - Designates whether TLS/SSL should be used when connecting to the IRC server + type: bool + default: false + part: + description: + - Designates whether user should part from channel after sending message or not. + Useful for when using a faux bot and not wanting join/parts between messages. + type: bool + default: true + style: + type: str + description: + - Text style for the message. Note italic does not work on some clients + choices: [ "bold", "underline", "reverse", "italic", "none" ] + default: none + +# informational: requirements for nodes +requirements: [ socket ] +author: + - "Jan-Piet Mens (@jpmens)" + - "Matt Martz (@sivel)" +''' + +EXAMPLES = ''' +- name: Send a message to an IRC channel from nick ansible + community.general.irc: + server: irc.example.net + channel: #t1 + msg: Hello world + +- name: Send a message to an IRC channel + local_action: + module: irc + port: 6669 + server: irc.example.net + channel: #t1 + msg: 'All finished at {{ ansible_date_time.iso8601 }}' + color: red + nick: ansibleIRC + +- name: Send a message to an IRC channel + local_action: + module: irc + port: 6669 + server: irc.example.net + channel: #t1 + nick_to: + - nick1 + - nick2 + msg: 'All finished at {{ ansible_date_time.iso8601 }}' + color: red + nick: ansibleIRC +''' + +# =========================================== +# IRC module support methods. +# + +import re +import socket +import ssl +import time +import traceback + +from ansible.module_utils.common.text.converters import to_native, to_bytes +from ansible.module_utils.basic import AnsibleModule + + +def send_msg(msg, server='localhost', port='6667', channel=None, nick_to=None, key=None, topic=None, + nick="ansible", color='none', passwd=False, timeout=30, use_ssl=False, part=True, style=None): + '''send message to IRC''' + nick_to = [] if nick_to is None else nick_to + + colornumbers = { + 'white': "00", + 'black': "01", + 'blue': "02", + 'green': "03", + 'red': "04", + 'brown': "05", + 'purple': "06", + 'orange': "07", + 'yellow': "08", + 'light_green': "09", + 'teal': "10", + 'light_cyan': "11", + 'light_blue': "12", + 'pink': "13", + 'gray': "14", + 'light_gray': "15", + } + + stylechoices = { + 'bold': "\x02", + 'underline': "\x1F", + 'reverse': "\x16", + 'italic': "\x1D", + } + + try: + styletext = stylechoices[style] + except Exception: + styletext = "" + + try: + colornumber = colornumbers[color] + colortext = "\x03" + colornumber + except Exception: + colortext = "" + + message = styletext + colortext + msg + + irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + if use_ssl: + irc = ssl.wrap_socket(irc) + irc.connect((server, int(port))) + + if passwd: + irc.send(to_bytes('PASS %s\r\n' % passwd)) + irc.send(to_bytes('NICK %s\r\n' % nick)) + irc.send(to_bytes('USER %s %s %s :ansible IRC\r\n' % (nick, nick, nick))) + motd = '' + start = time.time() + while 1: + motd += to_native(irc.recv(1024)) + # The server might send back a shorter nick than we specified (due to NICKLEN), + # so grab that and use it from now on (assuming we find the 00[1-4] response). + match = re.search(r'^:\S+ 00[1-4] (?P<nick>\S+) :', motd, flags=re.M) + if match: + nick = match.group('nick') + break + elif time.time() - start > timeout: + raise Exception('Timeout waiting for IRC server welcome response') + time.sleep(0.5) + + if channel: + if key: + irc.send(to_bytes('JOIN %s %s\r\n' % (channel, key))) + else: + irc.send(to_bytes('JOIN %s\r\n' % channel)) + + join = '' + start = time.time() + while 1: + join += to_native(irc.recv(1024)) + if re.search(r'^:\S+ 366 %s %s :' % (nick, channel), join, flags=re.M | re.I): + break + elif time.time() - start > timeout: + raise Exception('Timeout waiting for IRC JOIN response') + time.sleep(0.5) + + if topic is not None: + irc.send(to_bytes('TOPIC %s :%s\r\n' % (channel, topic))) + time.sleep(1) + + if nick_to: + for nick in nick_to: + irc.send(to_bytes('PRIVMSG %s :%s\r\n' % (nick, message))) + if channel: + irc.send(to_bytes('PRIVMSG %s :%s\r\n' % (channel, message))) + time.sleep(1) + if part: + if channel: + irc.send(to_bytes('PART %s\r\n' % channel)) + irc.send(to_bytes('QUIT\r\n')) + time.sleep(1) + irc.close() + +# =========================================== +# Main +# + + +def main(): + module = AnsibleModule( + argument_spec=dict( + server=dict(default='localhost'), + port=dict(type='int', default=6667), + nick=dict(default='ansible'), + nick_to=dict(required=False, type='list', elements='str'), + msg=dict(required=True), + color=dict(default="none", aliases=['colour'], choices=["white", "black", "blue", + "green", "red", "brown", + "purple", "orange", "yellow", + "light_green", "teal", "light_cyan", + "light_blue", "pink", "gray", + "light_gray", "none"]), + style=dict(default="none", choices=["underline", "reverse", "bold", "italic", "none"]), + channel=dict(required=False), + key=dict(no_log=True), + topic=dict(), + passwd=dict(no_log=True), + timeout=dict(type='int', default=30), + part=dict(type='bool', default=True), + use_ssl=dict(type='bool', default=False) + ), + supports_check_mode=True, + required_one_of=[['channel', 'nick_to']] + ) + + server = module.params["server"] + port = module.params["port"] + nick = module.params["nick"] + nick_to = module.params["nick_to"] + msg = module.params["msg"] + color = module.params["color"] + channel = module.params["channel"] + topic = module.params["topic"] + if topic and not channel: + module.fail_json(msg="When topic is specified, a channel is required.") + key = module.params["key"] + passwd = module.params["passwd"] + timeout = module.params["timeout"] + use_ssl = module.params["use_ssl"] + part = module.params["part"] + style = module.params["style"] + + try: + send_msg(msg, server, port, channel, nick_to, key, topic, nick, color, passwd, timeout, use_ssl, part, style) + except Exception as e: + module.fail_json(msg="unable to send to IRC: %s" % to_native(e), exception=traceback.format_exc()) + + module.exit_json(changed=False, channel=channel, nick=nick, + msg=msg) + + +if __name__ == '__main__': + main() |