diff options
| author | Simeon Simeonov | 2024-07-05 22:55:03 +0200 |
|---|---|---|
| committer | Simeon Simeonov | 2024-07-05 22:55:03 +0200 |
| commit | 37f8843f5fecc9bb4a5eb5b18eea35b1bbc16489 (patch) | |
| tree | b4aac0e5a5d587a9b1c4ba8ba8c22a73ad8049ae | |
| parent | e98d4a056f51f831f39c75ba0971fe766a77808c (diff) | |
| -rw-r--r-- | .ruff.toml | 109 | ||||
| -rw-r--r-- | Changelog | 4 | ||||
| -rw-r--r-- | README.md | 8 | ||||
| -rwxr-xr-x | beinc_generic_client.py | 41 | ||||
| -rwxr-xr-x | beinc_pull.py | 42 | ||||
| -rwxr-xr-x | beinc_server.py | 118 | ||||
| -rw-r--r-- | beinc_weechat.py | 66 |
7 files changed, 237 insertions, 151 deletions
diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..1037228 --- /dev/null +++ b/.ruff.toml | |||
| @@ -0,0 +1,109 @@ | |||
| 1 | cache-dir = "~/.cache/ruff" | ||
| 2 | indent-width = 4 | ||
| 3 | line-length = 79 | ||
| 4 | target-version = "py39" | ||
| 5 | |||
| 6 | [lint] | ||
| 7 | select = ["ALL", "D101", "D102", "D103", "D104"] | ||
| 8 | ignore = [ | ||
| 9 | "ANN", | ||
| 10 | "BLE001", | ||
| 11 | "COM812", | ||
| 12 | "D", | ||
| 13 | "EM101", # Exception must not use a string literal, assign to variable first | ||
| 14 | "EM102", # Exception must not use an f-string literal, assign to variable first | ||
| 15 | "ERA001", | ||
| 16 | "FBT001", | ||
| 17 | "FBT002", | ||
| 18 | "INP001", | ||
| 19 | "ISC001", | ||
| 20 | "N802", | ||
| 21 | "N806", | ||
| 22 | "PLR2004", | ||
| 23 | "PTH111", | ||
| 24 | "RUF012", | ||
| 25 | "RUF013", | ||
| 26 | "S101", | ||
| 27 | "T201", | ||
| 28 | "TRY003", | ||
| 29 | "TRY300", | ||
| 30 | "UP020" | ||
| 31 | ] | ||
| 32 | |||
| 33 | # D101 - Missing docstring in public class | ||
| 34 | # D102 - Missing docstring in public method | ||
| 35 | # D200 - One-line docstring should fit on one line | ||
| 36 | # D203 - 1 blank line required before class docstring | ||
| 37 | # D205 - 1 blank line required between summary line and description | ||
| 38 | # D403 - First word of the first line should be capitalized: `str` -> `Str` | ||
| 39 | # FBT001 - Boolean-typed positional argument in function definition | ||
| 40 | # FBT002 - Boolean default positional argument in function definition | ||
| 41 | # INP001 - File `beinc_weechat.py` is part of an implicit namespace package. Add an `__init__.py` | ||
| 42 | # N802 - Function name `do_GET` should be lowercase | ||
| 43 | # N806 - Variable `POST_data` in function should be lowercase | ||
| 44 | # PTH111 - `os.path.expanduser()` should be replaced by `Path.expanduser()` | ||
| 45 | # PLR2004 - Magic value used in comparison, consider replacing `200` with a constant variable | ||
| 46 | # RUF012 - Mutable class attributes should be annotated with `typing.ClassVar` | ||
| 47 | # RUF013 - PEP 484 prohibits implicit `Optional` | ||
| 48 | # S101 - Use of `assert` detected | ||
| 49 | # T201 - `print` found | ||
| 50 | # TRY003 - Avoid specifying long messages outside the exception class | ||
| 51 | # TRY300 - Consider moving this statement to an `else` block | ||
| 52 | # UP020 - Use builtin `open` | ||
| 53 | |||
| 54 | # Allow fix for all enabled rules (when `--fix`) is provided. | ||
| 55 | fixable = ["ALL"] | ||
| 56 | unfixable = [] | ||
| 57 | |||
| 58 | # custom settings | ||
| 59 | [lint.per-file-ignores] | ||
| 60 | "beinc_generic_client.py" = [ | ||
| 61 | "S310" # Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected | ||
| 62 | ] | ||
| 63 | "beinc_pull.py" = [ | ||
| 64 | "S310", # Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected | ||
| 65 | "TRY002", # Create your own exception | ||
| 66 | "TRY301" # Abstract `raise` to an inner function | ||
| 67 | ] | ||
| 68 | "beinc_weechat.py" = [ | ||
| 69 | "ARG001", # Unused function argument: `data` | ||
| 70 | "C901", # `beinc_cmd_target_handler` is too complex (13 > 10) | ||
| 71 | "DTZ005", # `datetime.datetime.now()` called without a `tz` argument | ||
| 72 | "PLR0912", # Too many branches (16 > 12) | ||
| 73 | "PLW0603", # Using the global statement to update `global_values` is discouraged | ||
| 74 | "PTH118", # `os.path.join()` should be replaced by `Path` with `/` operator | ||
| 75 | "S310", # Audit URL open for permitted schemes. Allowing use of `file:` or custom schemes is often unexpected | ||
| 76 | "TRY002", # Create your own exception | ||
| 77 | "TRY301" # Abstract `raise` to an inner function | ||
| 78 | ] | ||
| 79 | |||
| 80 | |||
| 81 | [format] | ||
| 82 | # Like Black, use double quotes for strings. | ||
| 83 | quote-style = "single" | ||
| 84 | |||
| 85 | # Like Black, indent with spaces, rather than tabs. | ||
| 86 | indent-style = "space" | ||
| 87 | |||
| 88 | # Like Black, respect magic trailing commas. | ||
| 89 | skip-magic-trailing-comma = true | ||
| 90 | |||
| 91 | # Like Black, automatically detect the appropriate line ending. | ||
| 92 | line-ending = "auto" | ||
| 93 | |||
| 94 | # Enable auto-formatting of code examples in docstrings. Markdown, | ||
| 95 | # reStructuredText code/literal blocks and doctests are all supported. | ||
| 96 | # | ||
| 97 | # This is currently disabled by default, but it is planned for this | ||
| 98 | # to be opt-out in the future. | ||
| 99 | docstring-code-format = false | ||
| 100 | |||
| 101 | # Set the line length limit used when formatting code snippets in | ||
| 102 | # docstrings. | ||
| 103 | # | ||
| 104 | # This only has an effect when the `docstring-code-format` setting is | ||
| 105 | # enabled. | ||
| 106 | docstring-code-line-length = "dynamic" | ||
| 107 | |||
| 108 | [lint.flake8-quotes] | ||
| 109 | inline-quotes = "single" | ||
| @@ -1,3 +1,7 @@ | |||
| 1 | v4.4: | ||
| 2 | - replace the functionality from the deprecated cgi module | ||
| 3 | - do some more format / linting (add .ruff.toml) | ||
| 4 | |||
| 1 | v4.3: | 5 | v4.3: |
| 2 | - remove obsolete SSL/TLS code | 6 | - remove obsolete SSL/TLS code |
| 3 | - use black alike coding style | 7 | - use black alike coding style |
| @@ -1,4 +1,4 @@ | |||
| 1 | Copyright (C) 2014-2022 - Simeon Simeonov | 1 | Copyright (C) 2014-2024 - Simeon Simeonov |
| 2 | See the end of the file for license conditions. | 2 | See the end of the file for license conditions. |
| 3 | 3 | ||
| 4 | 4 | ||
| @@ -90,13 +90,11 @@ your URL will be: https://hostname:port | |||
| 90 | ## Supported systems & requirements | 90 | ## Supported systems & requirements |
| 91 | 91 | ||
| 92 | Any system running the software required for the selected components. | 92 | Any system running the software required for the selected components. |
| 93 | All components tested on: Gentoo GNU/Linux, | 93 | All components tested on: Gentoo GNU/Linux, FreeBSD (12.x, 13.x) |
| 94 | Ubuntu GNU/Linux 18.4, | ||
| 95 | FreeBSD 12.x | ||
| 96 | 94 | ||
| 97 | 95 | ||
| 98 | ### Requirements | 96 | ### Requirements |
| 99 | All components: Python >= 3.6.* | 97 | All components: Python >= 3.9.* |
| 100 | 98 | ||
| 101 | beinc_server.py: pynotify >= 0.1 (optional) | 99 | beinc_server.py: pynotify >= 0.1 (optional) |
| 102 | beinc_weechat.py: Weechat >= 0.4.0 | 100 | beinc_weechat.py: Weechat >= 0.4.0 |
diff --git a/beinc_generic_client.py b/beinc_generic_client.py index 476287e..44e8698 100755 --- a/beinc_generic_client.py +++ b/beinc_generic_client.py | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -*- | ||
| 3 | 2 | ||
| 4 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) v4.3 | 3 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) |
| 5 | # Copyright (C) 2013-2022 Simeon Simeonov | 4 | # Copyright (C) 2013-2024 Simeon Simeonov |
| 6 | 5 | ||
| 7 | # This program is free software: you can redistribute it and/or modify | 6 | # This program is free software: you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License as published by | 7 | # it under the terms of the GNU General Public License as published by |
| @@ -17,12 +16,14 @@ | |||
| 17 | # You should have received a copy of the GNU General Public License | 16 | # You should have received a copy of the GNU General Public License |
| 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | """A generic BEINC client that can be used for testing or as a template""" | 18 | """A generic BEINC client that can be used for testing or as a template""" |
| 19 | |||
| 20 | import argparse | 20 | import argparse |
| 21 | import errno | 21 | import errno |
| 22 | import getpass | 22 | import getpass |
| 23 | import io | 23 | import io |
| 24 | import json | 24 | import json |
| 25 | import os | 25 | import os |
| 26 | import pathlib | ||
| 26 | import socket | 27 | import socket |
| 27 | import ssl | 28 | import ssl |
| 28 | import sys | 29 | import sys |
| @@ -30,7 +31,7 @@ import urllib.parse | |||
| 30 | import urllib.request | 31 | import urllib.request |
| 31 | 32 | ||
| 32 | __author__ = 'Simeon Simeonov' | 33 | __author__ = 'Simeon Simeonov' |
| 33 | __version__ = '4.3' | 34 | __version__ = '4.4' |
| 34 | __license__ = 'GPL3' | 35 | __license__ = 'GPL3' |
| 35 | 36 | ||
| 36 | 37 | ||
| @@ -55,14 +56,14 @@ def fetch_password(args_password): | |||
| 55 | except KeyboardInterrupt: | 56 | except KeyboardInterrupt: |
| 56 | eprint(os.linesep + 'Prompt terminated') | 57 | eprint(os.linesep + 'Prompt terminated') |
| 57 | sys.exit(errno.EACCES) | 58 | sys.exit(errno.EACCES) |
| 58 | elif os.path.isfile(args_password): | 59 | elif pathlib.Path(args_password).is_file(): |
| 59 | try: | 60 | try: |
| 60 | with io.open(args_password, 'r', encoding='utf-8') as fp: | 61 | with io.open(args_password, 'r', encoding='utf-8') as fp: |
| 61 | passwd = fp.readline() | 62 | passwd = fp.readline() |
| 62 | if passwd.strip(): | 63 | if passwd.strip(): |
| 63 | return passwd.strip() | 64 | return passwd.strip() |
| 64 | except Exception as e: | 65 | except Exception as exp: |
| 65 | eprint(f'Unable to open password file: {e}') | 66 | eprint(f'Unable to open password file: {exp}') |
| 66 | sys.exit(1) | 67 | sys.exit(1) |
| 67 | return args_password | 68 | return args_password |
| 68 | 69 | ||
| @@ -83,17 +84,14 @@ def pull_notifications(ssl_context, args): | |||
| 83 | response = urllib.request.urlopen( | 84 | response = urllib.request.urlopen( |
| 84 | args.url, | 85 | args.url, |
| 85 | data=urllib.parse.urlencode( | 86 | data=urllib.parse.urlencode( |
| 86 | ( | 87 | (('resource_name', args.rname), ('password', args.password)) |
| 87 | ('resource_name', args.rname), | ||
| 88 | ('password', args.password), | ||
| 89 | ) | ||
| 90 | ).encode('utf-8'), | 88 | ).encode('utf-8'), |
| 91 | timeout=args.socket_timeout, | 89 | timeout=args.socket_timeout, |
| 92 | context=ssl_context, | 90 | context=ssl_context, |
| 93 | ) | 91 | ) |
| 94 | response_dict = json.loads(response.read().decode('utf-8')) | 92 | response_dict = json.loads(response.read().decode('utf-8')) |
| 95 | if response.code != 200: | 93 | if response.code != 200: |
| 96 | raise socket.error(response_dict.get('message', '')) | 94 | raise OSError(response_dict.get('message', '')) |
| 97 | return response_dict['data']['messages'] | 95 | return response_dict['data']['messages'] |
| 98 | 96 | ||
| 99 | 97 | ||
| @@ -122,7 +120,7 @@ def push_notification(ssl_context, args): | |||
| 122 | ) | 120 | ) |
| 123 | response_dict = json.loads(response.read().decode('utf-8')) | 121 | response_dict = json.loads(response.read().decode('utf-8')) |
| 124 | if response.code != 200: | 122 | if response.code != 200: |
| 125 | raise socket.error(response_dict.get('message', '')) | 123 | raise OSError(response_dict.get('message', '')) |
| 126 | 124 | ||
| 127 | 125 | ||
| 128 | def main(inargs=None): | 126 | def main(inargs=None): |
| @@ -131,10 +129,7 @@ def main(inargs=None): | |||
| 131 | description='The following options are available' | 129 | description='The following options are available' |
| 132 | ) | 130 | ) |
| 133 | parser.add_argument( | 131 | parser.add_argument( |
| 134 | 'url', | 132 | 'url', metavar='URL', type=str, help='BEINC server destination URL' |
| 135 | metavar='URL', | ||
| 136 | type=str, | ||
| 137 | help='BEINC server destination URL', | ||
| 138 | ) | 133 | ) |
| 139 | parser.add_argument( | 134 | parser.add_argument( |
| 140 | '-c', | 135 | '-c', |
| @@ -242,14 +237,14 @@ def main(inargs=None): | |||
| 242 | push_notification(context, args) | 237 | push_notification(context, args) |
| 243 | print('OK') | 238 | print('OK') |
| 244 | sys.exit(0) | 239 | sys.exit(0) |
| 245 | except ssl.SSLError as e: | 240 | except ssl.SSLError as err: |
| 246 | eprint(f'BEINC SSL/TLS error: {e}') | 241 | eprint(f'BEINC SSL/TLS error: {err}') |
| 247 | sys.exit(errno.EPERM) | 242 | sys.exit(errno.EPERM) |
| 248 | except socket.error as e: | 243 | except OSError as err: |
| 249 | eprint(f'BEINC connection error: {e}') | 244 | eprint(f'BEINC connection error: {err}') |
| 250 | sys.exit(errno.EPERM) | 245 | sys.exit(errno.EPERM) |
| 251 | except Exception as e: | 246 | except Exception as exp: |
| 252 | eprint(f'BEINC generic client error: {e}') | 247 | eprint(f'BEINC generic client error: {exp}') |
| 253 | sys.exit(errno.EPERM) | 248 | sys.exit(errno.EPERM) |
| 254 | 249 | ||
| 255 | 250 | ||
diff --git a/beinc_pull.py b/beinc_pull.py index 118a08a..6ce9c2f 100755 --- a/beinc_pull.py +++ b/beinc_pull.py | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -*- | ||
| 3 | 2 | ||
| 4 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) v4.3 | 3 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) |
| 5 | # Copyright (C) 2013-2022 Simeon Simeonov | 4 | # Copyright (C) 2013-2024 Simeon Simeonov |
| 6 | 5 | ||
| 7 | # This program is free software: you can redistribute it and/or modify | 6 | # This program is free software: you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License as published by | 7 | # it under the terms of the GNU General Public License as published by |
| @@ -17,14 +16,15 @@ | |||
| 17 | # You should have received a copy of the GNU General Public License | 16 | # You should have received a copy of the GNU General Public License |
| 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | """A simple client that pulls notifications from a BEINC server""" | 18 | """A simple client that pulls notifications from a BEINC server""" |
| 19 | |||
| 20 | import argparse | 20 | import argparse |
| 21 | import errno | 21 | import errno |
| 22 | import getpass | 22 | import getpass |
| 23 | import io | 23 | import io |
| 24 | import json | 24 | import json |
| 25 | import os | 25 | import os |
| 26 | import pathlib | ||
| 26 | import sched | 27 | import sched |
| 27 | import socket | ||
| 28 | import ssl | 28 | import ssl |
| 29 | import sys | 29 | import sys |
| 30 | import time | 30 | import time |
| @@ -38,7 +38,7 @@ except ImportError: | |||
| 38 | 38 | ||
| 39 | 39 | ||
| 40 | __author__ = 'Simeon Simeonov' | 40 | __author__ = 'Simeon Simeonov' |
| 41 | __version__ = '4.3' | 41 | __version__ = '4.4' |
| 42 | __license__ = 'GPL3' | 42 | __license__ = 'GPL3' |
| 43 | 43 | ||
| 44 | 44 | ||
| @@ -63,14 +63,14 @@ def fetch_password(args_password): | |||
| 63 | except KeyboardInterrupt: | 63 | except KeyboardInterrupt: |
| 64 | eprint(os.linesep + 'Prompt terminated') | 64 | eprint(os.linesep + 'Prompt terminated') |
| 65 | sys.exit(errno.EACCES) | 65 | sys.exit(errno.EACCES) |
| 66 | elif os.path.isfile(args_password): | 66 | elif pathlib.Path(args_password).is_file(): |
| 67 | try: | 67 | try: |
| 68 | with io.open(args_password, 'r', encoding='utf-8') as fp: | 68 | with io.open(args_password, 'r', encoding='utf-8') as fp: |
| 69 | passwd = fp.readline() | 69 | passwd = fp.readline() |
| 70 | if passwd.strip(): | 70 | if passwd.strip(): |
| 71 | return passwd.strip() | 71 | return passwd.strip() |
| 72 | except Exception as e: | 72 | except Exception as exp: |
| 73 | eprint(f'Unable to open password file: {e}') | 73 | eprint(f'Unable to open password file: {exp}') |
| 74 | sys.exit(1) | 74 | sys.exit(1) |
| 75 | return args_password | 75 | return args_password |
| 76 | 76 | ||
| @@ -98,8 +98,7 @@ def display_notification(args, title, message): | |||
| 98 | if not pynotify.init('BEINC Notify'): | 98 | if not pynotify.init('BEINC Notify'): |
| 99 | raise Exception('There was a problem with libnotify') | 99 | raise Exception('There was a problem with libnotify') |
| 100 | notification_obj = pynotify.Notification( | 100 | notification_obj = pynotify.Notification( |
| 101 | summary=title, | 101 | summary=title, message=message |
| 102 | message=message, | ||
| 103 | ) | 102 | ) |
| 104 | notification_obj.timeout = 1000 * args.osd_timeout | 103 | notification_obj.timeout = 1000 * args.osd_timeout |
| 105 | notification_obj.set_category('im.received') | 104 | notification_obj.set_category('im.received') |
| @@ -139,25 +138,23 @@ def pull_notifications(scheduler, args): | |||
| 139 | ) | 138 | ) |
| 140 | response_dict = json.loads(response.read().decode('utf-8')) | 139 | response_dict = json.loads(response.read().decode('utf-8')) |
| 141 | if response.code != 200: | 140 | if response.code != 200: |
| 142 | raise socket.error(response_dict.get('message', '')) | 141 | raise OSError(response_dict.get('message', '')) |
| 143 | for entry in response_dict['data']['messages']: | 142 | for entry in response_dict['data']['messages']: |
| 144 | display_notification( | 143 | display_notification( |
| 145 | args, | 144 | args, entry.get('title', ''), entry.get('message', '') |
| 146 | entry.get('title', ''), | ||
| 147 | entry.get('message', ''), | ||
| 148 | ) | 145 | ) |
| 149 | response.close() | 146 | response.close() |
| 150 | scheduler.enter( | 147 | scheduler.enter( |
| 151 | args.frequency, 1, pull_notifications, (scheduler, args) | 148 | args.frequency, 1, pull_notifications, (scheduler, args) |
| 152 | ) | 149 | ) |
| 153 | except ssl.SSLError as e: | 150 | except ssl.SSLError as err: |
| 154 | eprint(f'BEINC SSL/TLS error: {e}') | 151 | eprint(f'BEINC SSL/TLS error: {err}') |
| 155 | sys.exit(errno.EPERM) | 152 | sys.exit(errno.EPERM) |
| 156 | except socket.error as e: | 153 | except OSError as err: |
| 157 | eprint(f'BEINC connection error: {e}') | 154 | eprint(f'BEINC connection error: {err}') |
| 158 | sys.exit(errno.EPERM) | 155 | sys.exit(errno.EPERM) |
| 159 | except Exception as e: | 156 | except Exception as exp: |
| 160 | eprint(f'BEINC generic client error: {e}') | 157 | eprint(f'BEINC generic client error: {exp}') |
| 161 | sys.exit(errno.EPERM) | 158 | sys.exit(errno.EPERM) |
| 162 | 159 | ||
| 163 | 160 | ||
| @@ -167,10 +164,7 @@ def main(inargs=None): | |||
| 167 | description='The following options are available' | 164 | description='The following options are available' |
| 168 | ) | 165 | ) |
| 169 | parser.add_argument( | 166 | parser.add_argument( |
| 170 | 'url', | 167 | 'url', metavar='URL', type=str, help='BEINC server destination URL' |
| 171 | metavar='URL', | ||
| 172 | type=str, | ||
| 173 | help='BEINC server destination URL', | ||
| 174 | ) | 168 | ) |
| 175 | parser.add_argument( | 169 | parser.add_argument( |
| 176 | '-c', | 170 | '-c', |
diff --git a/beinc_server.py b/beinc_server.py index 0098fba..647d7f1 100755 --- a/beinc_server.py +++ b/beinc_server.py | |||
| @@ -1,8 +1,7 @@ | |||
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -*- | ||
| 3 | 2 | ||
| 4 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) v4.3 | 3 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) |
| 5 | # Copyright (C) 2013-2023 Simeon Simeonov | 4 | # Copyright (C) 2013-2024 Simeon Simeonov |
| 6 | 5 | ||
| 7 | # This program is free software: you can redistribute it and/or modify | 6 | # This program is free software: you can redistribute it and/or modify |
| 8 | # it under the terms of the GNU General Public License as published by | 7 | # it under the terms of the GNU General Public License as published by |
| @@ -16,14 +15,16 @@ | |||
| 16 | 15 | ||
| 17 | # You should have received a copy of the GNU General Public License | 16 | # You should have received a copy of the GNU General Public License |
| 18 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 19 | 18 | """BEINC standalone server implementation""" | |
| 20 | 19 | ||
| 21 | import argparse | 20 | import argparse |
| 21 | import contextlib | ||
| 22 | import errno | 22 | import errno |
| 23 | import io | 23 | import io |
| 24 | import json | 24 | import json |
| 25 | import logging | 25 | import logging |
| 26 | import os | 26 | import os |
| 27 | import pathlib | ||
| 27 | import ssl | 28 | import ssl |
| 28 | import sys | 29 | import sys |
| 29 | import urllib.parse | 30 | import urllib.parse |
| @@ -38,7 +39,7 @@ except ImportError: | |||
| 38 | 39 | ||
| 39 | 40 | ||
| 40 | __author__ = 'Simeon Simeonov' | 41 | __author__ = 'Simeon Simeonov' |
| 41 | __version__ = '4.3' | 42 | __version__ = '4.4' |
| 42 | __license__ = 'GPL3' | 43 | __license__ = 'GPL3' |
| 43 | 44 | ||
| 44 | 45 | ||
| @@ -48,24 +49,24 @@ BEINC_OSD_TYPE_PYNOTIFY = 1 | |||
| 48 | BEINC_CURRENT_CONFIG_VERSION = 3 | 49 | BEINC_CURRENT_CONFIG_VERSION = 3 |
| 49 | 50 | ||
| 50 | 51 | ||
| 51 | class BEINCError400(Exception): | 52 | class BEINC400Error(Exception): |
| 52 | """BEINCError400""" | 53 | """BEINC400Error""" |
| 53 | 54 | ||
| 54 | 55 | ||
| 55 | class BEINCError401(Exception): | 56 | class BEINC401Error(Exception): |
| 56 | """BEINCError401""" | 57 | """BEINC401Error""" |
| 57 | 58 | ||
| 58 | 59 | ||
| 59 | class BEINCError403(Exception): | 60 | class BEINC403Error(Exception): |
| 60 | """BEINCError403""" | 61 | """BEINC403Error""" |
| 61 | 62 | ||
| 62 | 63 | ||
| 63 | class BEINCError404(Exception): | 64 | class BEINC404Error(Exception): |
| 64 | """BEINCError404""" | 65 | """BEINC404Error""" |
| 65 | 66 | ||
| 66 | 67 | ||
| 67 | class BEINCError405(Exception): | 68 | class BEINC405Error(Exception): |
| 68 | """BEINCError405""" | 69 | """BEINC405Error""" |
| 69 | 70 | ||
| 70 | 71 | ||
| 71 | def eprint(*arg, **kwargs): | 72 | def eprint(*arg, **kwargs): |
| @@ -79,15 +80,15 @@ def beinc_login_required(method): | |||
| 79 | @wraps(method) | 80 | @wraps(method) |
| 80 | def wrapper(self, data, *arg, **kwargs): | 81 | def wrapper(self, data, *arg, **kwargs): |
| 81 | if data.get('resource_name') is None: | 82 | if data.get('resource_name') is None: |
| 82 | raise BEINCError403('Resource-name missing') | 83 | raise BEINC403Error('Resource-name missing') |
| 83 | if data.get('password') is None: | 84 | if data.get('password') is None: |
| 84 | raise BEINCError401('Password missing') | 85 | raise BEINC401Error('Password missing') |
| 85 | try: | 86 | try: |
| 86 | instance = self.server.instances[data.get('resource_name')] | 87 | instance = self.server.instances[data.get('resource_name')] |
| 87 | except Exception: | 88 | except Exception: |
| 88 | raise BEINCError401('Wrong instance or password') from None | 89 | raise BEINC401Error('Wrong instance or password') from None |
| 89 | if not instance.password_match(data.get('password')): | 90 | if not instance.password_match(data.get('password')): |
| 90 | raise BEINCError401('Wrong instance or password') | 91 | raise BEINC401Error('Wrong instance or password') |
| 91 | return method(self, data, *arg, **kwargs) | 92 | return method(self, data, *arg, **kwargs) |
| 92 | 93 | ||
| 93 | return wrapper | 94 | return wrapper |
| @@ -124,10 +125,10 @@ class BEINCInstance: | |||
| 124 | ) | 125 | ) |
| 125 | self._osd_notification.set_category('im.received') | 126 | self._osd_notification.set_category('im.received') |
| 126 | self._osd_type = BEINC_OSD_TYPE_PYNOTIFY | 127 | self._osd_type = BEINC_OSD_TYPE_PYNOTIFY |
| 127 | except Exception as e: | 128 | except Exception as exp: |
| 128 | eprint( | 129 | eprint( |
| 129 | f'Unable to set up a pynotify notification object ' | 130 | f'Unable to set up a pynotify notification object ' |
| 130 | f'for "{self._name}" ({e})' | 131 | f'for "{self._name}" ({exp})' |
| 131 | ) | 132 | ) |
| 132 | sys.exit(errno.EPERM) | 133 | sys.exit(errno.EPERM) |
| 133 | 134 | ||
| @@ -217,13 +218,11 @@ class BEINCCustomHandler(BaseHTTPRequestHandler): | |||
| 217 | if headers is None: | 218 | if headers is None: |
| 218 | headers = {} | 219 | headers = {} |
| 219 | if 'content-length' in headers: | 220 | if 'content-length' in headers: |
| 220 | try: | 221 | with contextlib.suppress(ValueError): |
| 221 | clen = int(headers['content-length']) | 222 | clen = int(headers['content-length']) |
| 222 | except ValueError: | ||
| 223 | pass | ||
| 224 | return dict(urllib.parse.parse_qsl(fp.read(clen).decode('utf-8'))) | 223 | return dict(urllib.parse.parse_qsl(fp.read(clen).decode('utf-8'))) |
| 225 | except Exception as e: | 224 | except Exception as exp: |
| 226 | raise BEINCError400('Invalid POST request') from e | 225 | raise BEINC400Error('Invalid POST request') from exp |
| 227 | 226 | ||
| 228 | def do_POST(self): | 227 | def do_POST(self): |
| 229 | """Handle POST requests""" | 228 | """Handle POST requests""" |
| @@ -245,18 +244,18 @@ class BEINCCustomHandler(BaseHTTPRequestHandler): | |||
| 245 | elif self.path.strip('/') == 'beinc/pull': | 244 | elif self.path.strip('/') == 'beinc/pull': |
| 246 | result = self._handle_pull(POST_data) | 245 | result = self._handle_pull(POST_data) |
| 247 | self._render_to_JSON_response(result) | 246 | self._render_to_JSON_response(result) |
| 248 | except BEINCError400 as e: | 247 | except BEINC400Error as err: |
| 249 | self._generate_json_error(400, str(e)) | 248 | self._generate_json_error(400, str(err)) |
| 250 | except BEINCError401 as e: | 249 | except BEINC401Error as err: |
| 251 | self._generate_json_error(401, str(e)) | 250 | self._generate_json_error(401, str(err)) |
| 252 | except BEINCError403 as e: | 251 | except BEINC403Error as err: |
| 253 | self._generate_json_error(403, str(e)) | 252 | self._generate_json_error(403, str(err)) |
| 254 | except BEINCError404 as e: | 253 | except BEINC404Error as err: |
| 255 | self._generate_json_error(404, str(e)) | 254 | self._generate_json_error(404, str(err)) |
| 256 | except BEINCError405 as e: | 255 | except BEINC405Error as err: |
| 257 | self._generate_json_error(405, str(e)) | 256 | self._generate_json_error(405, str(err)) |
| 258 | except Exception as e: | 257 | except Exception as exp: |
| 259 | self._generate_json_error(500, f'Unexpected error: {e}') | 258 | self._generate_json_error(500, f'Unexpected error: {exp}') |
| 260 | 259 | ||
| 261 | def do_GET(self): | 260 | def do_GET(self): |
| 262 | """Handle GET Requests""" | 261 | """Handle GET Requests""" |
| @@ -266,25 +265,19 @@ class BEINCCustomHandler(BaseHTTPRequestHandler): | |||
| 266 | def _handle_push(self, data): | 265 | def _handle_push(self, data): |
| 267 | """Handle push""" | 266 | """Handle push""" |
| 268 | instance = self.server.instances[data.get('resource_name')] | 267 | instance = self.server.instances[data.get('resource_name')] |
| 269 | try: | 268 | instance.send_message(data.get('title'), data.get('message')) |
| 270 | instance.send_message(data.get('title'), data.get('message')) | 269 | return {'message': 'OK. Sent.'} |
| 271 | return {'message': 'OK. Sent.'} | ||
| 272 | except Exception as e: | ||
| 273 | self._generate_json_error(500, str(e)) | ||
| 274 | 270 | ||
| 275 | @beinc_login_required | 271 | @beinc_login_required |
| 276 | def _handle_pull(self, data): | 272 | def _handle_pull(self, data): |
| 277 | """Handle pull""" | 273 | """Handle pull""" |
| 278 | instance = self.server.instances[data.get('resource_name')] | 274 | instance = self.server.instances[data.get('resource_name')] |
| 279 | try: | 275 | if not instance.queueable: |
| 280 | if not instance.queueable: | 276 | raise BEINC405Error('This instance does not support queuing') |
| 281 | raise BEINCError405('This instance does not support queuing') | 277 | return { |
| 282 | return { | 278 | 'message': 'OK. Fetched.', |
| 283 | 'message': 'OK. Fetched.', | 279 | 'data': {'messages': instance.get_queue()}, |
| 284 | 'data': {'messages': instance.get_queue()}, | 280 | } |
| 285 | } | ||
| 286 | except Exception as e: | ||
| 287 | self._generate_json_error(500, str(e)) | ||
| 288 | 281 | ||
| 289 | def _generate_json_error(self, code, message): | 282 | def _generate_json_error(self, code, message): |
| 290 | """ | 283 | """ |
| @@ -349,15 +342,13 @@ class BEINCNotifyServer(HTTPServer): | |||
| 349 | for instance in self._config['server']['instances']: | 342 | for instance in self._config['server']['instances']: |
| 350 | self._instances[instance['name']] = BEINCInstance(instance) | 343 | self._instances[instance['name']] = BEINCInstance(instance) |
| 351 | logger.info('Instance %s added', instance['name']) | 344 | logger.info('Instance %s added', instance['name']) |
| 352 | except Exception as e: | 345 | except Exception as exp: |
| 353 | eprint(f"Unable to create instance \"{instance['name']}\": {e}") | 346 | eprint(f"Unable to create instance \"{instance['name']}\": {exp}") |
| 354 | sys.exit(1) | 347 | sys.exit(1) |
| 355 | 348 | ||
| 356 | @property | 349 | @property |
| 357 | def instances(self): | 350 | def instances(self): |
| 358 | """ | 351 | """a property that returns the instance list (read-only)""" |
| 359 | a property that returns the instance list (read-only) | ||
| 360 | """ | ||
| 361 | return self._instances | 352 | return self._instances |
| 362 | 353 | ||
| 363 | 354 | ||
| @@ -424,11 +415,11 @@ if __name__ == '__main__': | |||
| 424 | try: | 415 | try: |
| 425 | with io.open(args.config_file, 'r', encoding='utf-8') as fp: | 416 | with io.open(args.config_file, 'r', encoding='utf-8') as fp: |
| 426 | config_dict = json.load(fp) | 417 | config_dict = json.load(fp) |
| 427 | except Exception as e: | 418 | except Exception as exp: |
| 428 | eprint(f'Unable to parse {args.config_file}: {e}') | 419 | eprint(f'Unable to parse {args.config_file}: {exp}') |
| 429 | sys.exit(errno.EIO) | 420 | sys.exit(errno.EIO) |
| 430 | try: | 421 | try: |
| 431 | if os.path.isfile(args.logger_config): | 422 | if pathlib.Path(args.logger_config).is_file(): |
| 432 | fileConfig(args.logger_config) | 423 | fileConfig(args.logger_config) |
| 433 | logger = logging.getLogger(args.logger_name) | 424 | logger = logging.getLogger(args.logger_name) |
| 434 | else: | 425 | else: |
| @@ -456,8 +447,7 @@ if __name__ == '__main__': | |||
| 456 | 'ssl_ciphers' | 447 | 'ssl_ciphers' |
| 457 | ) | 448 | ) |
| 458 | beinc_server = BEINCNotifyServer( | 449 | beinc_server = BEINCNotifyServer( |
| 459 | (args.hostname, args.port), | 450 | (args.hostname, args.port), BEINCCustomHandler |
| 460 | BEINCCustomHandler, | ||
| 461 | ) | 451 | ) |
| 462 | beinc_server.set_config(config_dict) | 452 | beinc_server.set_config(config_dict) |
| 463 | if ssl_certificate and ssl_private_key: | 453 | if ssl_certificate and ssl_private_key: |
| @@ -474,7 +464,7 @@ if __name__ == '__main__': | |||
| 474 | beinc_server.serve_forever() | 464 | beinc_server.serve_forever() |
| 475 | except KeyboardInterrupt: | 465 | except KeyboardInterrupt: |
| 476 | print('\n\nTerminating...') | 466 | print('\n\nTerminating...') |
| 477 | except Exception as e: | 467 | except Exception as exp: |
| 478 | eprint(f'BEINCServer critical error: {e}') | 468 | eprint(f'BEINCServer critical error: {exp}') |
| 479 | sys.exit(1) | 469 | sys.exit(1) |
| 480 | sys.exit(0) | 470 | sys.exit(0) |
diff --git a/beinc_weechat.py b/beinc_weechat.py index b3550d8..cdbfe1f 100644 --- a/beinc_weechat.py +++ b/beinc_weechat.py | |||
| @@ -1,7 +1,5 @@ | |||
| 1 | # -*- coding: utf-8 -*- | 1 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) |
| 2 | 2 | # Copyright (C) 2013-2024 Simeon Simeonov | |
| 3 | # Blackmore's Enhanced IRC-Notification Collection (BEINC) v4.3 | ||
| 4 | # Copyright (C) 2013-2022 Simeon Simeonov | ||
| 5 | 3 | ||
| 6 | # This program is free software: you can redistribute it and/or modify | 4 | # This program is free software: you can redistribute it and/or modify |
| 7 | # it under the terms of the GNU General Public License as published by | 5 | # it under the terms of the GNU General Public License as published by |
| @@ -16,11 +14,11 @@ | |||
| 16 | # You should have received a copy of the GNU General Public License | 14 | # You should have received a copy of the GNU General Public License |
| 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 18 | """BEINC client for Weechat""" | 16 | """BEINC client for Weechat""" |
| 17 | |||
| 19 | import datetime | 18 | import datetime |
| 20 | import io | 19 | import io |
| 21 | import json | 20 | import json |
| 22 | import os | 21 | import os |
| 23 | import socket | ||
| 24 | import ssl | 22 | import ssl |
| 25 | import urllib.parse | 23 | import urllib.parse |
| 26 | import urllib.request | 24 | import urllib.request |
| @@ -28,7 +26,7 @@ import urllib.request | |||
| 28 | import weechat | 26 | import weechat |
| 29 | 27 | ||
| 30 | __author__ = 'Simeon Simeonov' | 28 | __author__ = 'Simeon Simeonov' |
| 31 | __version__ = '4.3' | 29 | __version__ = '4.4' |
| 32 | __license__ = 'GPL3' | 30 | __license__ = 'GPL3' |
| 33 | 31 | ||
| 34 | 32 | ||
| @@ -178,19 +176,18 @@ class WeechatTarget: | |||
| 178 | try: | 176 | try: |
| 179 | title = self._fetch_formatted_str(self._pm_title_template, values) | 177 | title = self._fetch_formatted_str(self._pm_title_template, values) |
| 180 | message = self._fetch_formatted_str( | 178 | message = self._fetch_formatted_str( |
| 181 | self._pm_message_template, | 179 | self._pm_message_template, values |
| 182 | values, | ||
| 183 | ) | 180 | ) |
| 184 | if not self._send_beinc_message(title, message) and self._debug: | 181 | if not self._send_beinc_message(title, message) and self._debug: |
| 185 | beinc_prnt( | 182 | beinc_prnt( |
| 186 | f'BEINC DEBUG: send_private_message_notification-ERROR ' | 183 | f'BEINC DEBUG: send_private_message_notification-ERROR ' |
| 187 | f'for "{self._name}": _send_beinc_message -> False' | 184 | f'for "{self._name}": _send_beinc_message -> False' |
| 188 | ) | 185 | ) |
| 189 | except Exception as e: | 186 | except Exception as exp: |
| 190 | if self._debug: | 187 | if self._debug: |
| 191 | beinc_prnt( | 188 | beinc_prnt( |
| 192 | f'BEINC DEBUG: send_private_message_notification-ERROR ' | 189 | f'BEINC DEBUG: send_private_message_notification-ERROR ' |
| 193 | f'for "{self._name}": {e}' | 190 | f'for "{self._name}": {exp}' |
| 194 | ) | 191 | ) |
| 195 | 192 | ||
| 196 | def send_channel_message_notification(self, values): | 193 | def send_channel_message_notification(self, values): |
| @@ -210,11 +207,11 @@ class WeechatTarget: | |||
| 210 | f'BEINC DEBUG: send_channel_message_notification-ERROR ' | 207 | f'BEINC DEBUG: send_channel_message_notification-ERROR ' |
| 211 | f'for "{self._name}": _send_beinc_message -> False' | 208 | f'for "{self._name}": _send_beinc_message -> False' |
| 212 | ) | 209 | ) |
| 213 | except Exception as e: | 210 | except Exception as exp: |
| 214 | if self._debug: | 211 | if self._debug: |
| 215 | beinc_prnt( | 212 | beinc_prnt( |
| 216 | f'BEINC DEBUG: send_channel_message_notification-ERROR ' | 213 | f'BEINC DEBUG: send_channel_message_notification-ERROR ' |
| 217 | f'for "{self._name}": {e}' | 214 | f'for "{self._name}": {exp}' |
| 218 | ) | 215 | ) |
| 219 | 216 | ||
| 220 | def send_notify_message_notification(self, values): | 217 | def send_notify_message_notification(self, values): |
| @@ -234,11 +231,11 @@ class WeechatTarget: | |||
| 234 | f'BEINC DEBUG: send_notify_message_notification-ERROR ' | 231 | f'BEINC DEBUG: send_notify_message_notification-ERROR ' |
| 235 | f'for "{self._name}": _send_beinc_message -> False' | 232 | f'for "{self._name}": _send_beinc_message -> False' |
| 236 | ) | 233 | ) |
| 237 | except Exception as e: | 234 | except Exception as exp: |
| 238 | if self._debug: | 235 | if self._debug: |
| 239 | beinc_prnt( | 236 | beinc_prnt( |
| 240 | f'BEINC DEBUG: send_notify_message_notification-ERROR ' | 237 | f'BEINC DEBUG: send_notify_message_notification-ERROR ' |
| 241 | f'for "{self._name}": {e}' | 238 | f'for "{self._name}": {exp}' |
| 242 | ) | 239 | ) |
| 243 | 240 | ||
| 244 | def send_broadcast_notification(self, message): | 241 | def send_broadcast_notification(self, message): |
| @@ -256,11 +253,11 @@ class WeechatTarget: | |||
| 256 | f'BEINC DEBUG: send_broadcast_notification-ERROR ' | 253 | f'BEINC DEBUG: send_broadcast_notification-ERROR ' |
| 257 | f'for "{self._name}": _send_beinc_message -> False' | 254 | f'for "{self._name}": _send_beinc_message -> False' |
| 258 | ) | 255 | ) |
| 259 | except Exception as e: | 256 | except Exception as exp: |
| 260 | if self._debug: | 257 | if self._debug: |
| 261 | beinc_prnt( | 258 | beinc_prnt( |
| 262 | f'BEINC DEBUG: send_broadcast_notification-ERROR ' | 259 | f'BEINC DEBUG: send_broadcast_notification-ERROR ' |
| 263 | f'for "{self._name}": {e}' | 260 | f'for "{self._name}": {exp}' |
| 264 | ) | 261 | ) |
| 265 | 262 | ||
| 266 | def _context_setup(self): | 263 | def _context_setup(self): |
| @@ -282,12 +279,12 @@ class WeechatTarget: | |||
| 282 | context.set_ciphers(self._ssl_ciphers) | 279 | context.set_ciphers(self._ssl_ciphers) |
| 283 | self._context = context | 280 | self._context = context |
| 284 | return True | 281 | return True |
| 285 | except ssl.SSLError as e: | 282 | except ssl.SSLError as err: |
| 286 | if self._debug: | 283 | if self._debug: |
| 287 | beinc_prnt(f'BEINC DEBUG: SSL/TLS error: {e}\n') | 284 | beinc_prnt(f'BEINC DEBUG: SSL/TLS error: {err}\n') |
| 288 | except Exception as e: | 285 | except Exception as exp: |
| 289 | if self._debug: | 286 | if self._debug: |
| 290 | beinc_prnt(f'BEINC DEBUG: Generic context error: {e}\n') | 287 | beinc_prnt(f'BEINC DEBUG: Generic context error: {exp}\n') |
| 291 | self._context = None | 288 | self._context = None |
| 292 | return False | 289 | return False |
| 293 | 290 | ||
| @@ -351,7 +348,7 @@ class WeechatTarget: | |||
| 351 | ) | 348 | ) |
| 352 | response_dict = json.loads(response.read().decode('utf-8')) | 349 | response_dict = json.loads(response.read().decode('utf-8')) |
| 353 | if response.code != 200: | 350 | if response.code != 200: |
| 354 | raise socket.error(response_dict.get('message', '')) | 351 | raise OSError(response_dict.get('message', '')) |
| 355 | if self._debug: | 352 | if self._debug: |
| 356 | beinc_prnt( | 353 | beinc_prnt( |
| 357 | "BEINC DEBUG: Server responded: " | 354 | "BEINC DEBUG: Server responded: " |
| @@ -359,15 +356,15 @@ class WeechatTarget: | |||
| 359 | ) | 356 | ) |
| 360 | self._last_message = datetime.datetime.now() | 357 | self._last_message = datetime.datetime.now() |
| 361 | return True | 358 | return True |
| 362 | except ssl.SSLError as e: | 359 | except ssl.SSLError as err: |
| 363 | if self._debug: | 360 | if self._debug: |
| 364 | beinc_prnt(f'BEINC DEBUG: SSL/TLS error: {e}\n') | 361 | beinc_prnt(f'BEINC DEBUG: SSL/TLS error: {err}\n') |
| 365 | except socket.error as e: | 362 | except OSError as err: |
| 366 | if self._debug: | 363 | if self._debug: |
| 367 | beinc_prnt(f'BEINC DEBUG: Connection error: {e}\n') | 364 | beinc_prnt(f'BEINC DEBUG: Connection error: {err}\n') |
| 368 | except Exception as e: | 365 | except Exception as exp: |
| 369 | if self._debug: | 366 | if self._debug: |
| 370 | beinc_prnt(f'BEINC DEBUG: Unable to send message: {e}\n') | 367 | beinc_prnt(f'BEINC DEBUG: Unable to send message: {exp}\n') |
| 371 | return False | 368 | return False |
| 372 | 369 | ||
| 373 | 370 | ||
| @@ -398,7 +395,7 @@ def beinc_cmd_target_handler(cmd_tokens): | |||
| 398 | if cmd_tokens[0] == 'list': | 395 | if cmd_tokens[0] == 'list': |
| 399 | beinc_prnt('--- Globals ---') | 396 | beinc_prnt('--- Globals ---') |
| 400 | for key, value in global_values.items(): | 397 | for key, value in global_values.items(): |
| 401 | beinc_prnt(f'{key} -> {str(value)}') | 398 | beinc_prnt(f'{key} -> {value}') |
| 402 | beinc_prnt('--- Targets ---') | 399 | beinc_prnt('--- Targets ---') |
| 403 | for target in target_list: | 400 | for target in target_list: |
| 404 | beinc_prnt(str(target)) | 401 | beinc_prnt(str(target)) |
| @@ -539,8 +536,7 @@ def beinc_init(): | |||
| 539 | 536 | ||
| 540 | try: | 537 | try: |
| 541 | beinc_config_file_str = os.path.join( | 538 | beinc_config_file_str = os.path.join( |
| 542 | weechat.info_get('weechat_dir', ''), | 539 | weechat.info_get('weechat_dir', ''), 'beinc_weechat.json' |
| 543 | 'beinc_weechat.json', | ||
| 544 | ) | 540 | ) |
| 545 | beinc_prnt(f'Parsing {beinc_config_file_str}...') | 541 | beinc_prnt(f'Parsing {beinc_config_file_str}...') |
| 546 | custom_error = 'load error' | 542 | custom_error = 'load error' |
| @@ -565,8 +561,8 @@ def beinc_init(): | |||
| 565 | for target in config_dict['irc_client']['targets']: | 561 | for target in config_dict['irc_client']['targets']: |
| 566 | try: | 562 | try: |
| 567 | new_target = WeechatTarget(target) | 563 | new_target = WeechatTarget(target) |
| 568 | except Exception as e: | 564 | except Exception as exp: |
| 569 | beinc_prnt(f'Unable to add target: {e}') | 565 | beinc_prnt(f'Unable to add target: {exp}') |
| 570 | continue | 566 | continue |
| 571 | if new_target.channel_messages_policy: | 567 | if new_target.channel_messages_policy: |
| 572 | global_values['global_channel_messages_policy'] = True | 568 | global_values['global_channel_messages_policy'] = True |
| @@ -577,10 +573,10 @@ def beinc_init(): | |||
| 577 | target_list.append(new_target) | 573 | target_list.append(new_target) |
| 578 | beinc_prnt(f'BEINC target "{new_target.name}" added') | 574 | beinc_prnt(f'BEINC target "{new_target.name}" added') |
| 579 | beinc_prnt('Done!') | 575 | beinc_prnt('Done!') |
| 580 | except Exception as e: | 576 | except Exception as exp: |
| 581 | beinc_prnt( | 577 | beinc_prnt( |
| 582 | f'ERROR: unable to parse {beinc_config_file_str}: ' | 578 | f'ERROR: unable to parse {beinc_config_file_str}: ' |
| 583 | f'{custom_error} - {e}\nBEINC is now disabled' | 579 | f'{custom_error} - {exp}\nBEINC is now disabled' |
| 584 | ) | 580 | ) |
| 585 | enabled = False | 581 | enabled = False |
| 586 | # do not return error / exit the script | 582 | # do not return error / exit the script |
| @@ -594,7 +590,7 @@ weechat.register( | |||
| 594 | __author__, | 590 | __author__, |
| 595 | __version__, | 591 | __version__, |
| 596 | __license__, | 592 | __license__, |
| 597 | 'Blackmore\'s Extended IRC Notification Collection (Weechat Client)', | 593 | "Blackmore's Extended IRC Notification Collection (Weechat Client)", |
| 598 | '', | 594 | '', |
| 599 | '', | 595 | '', |
| 600 | ) | 596 | ) |
