diff -r 3fc8dfeb6ebe -r b99e7fd55fd3 src/eric7/Network/IRC/IrcUtilities.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/eric7/Network/IRC/IrcUtilities.py Thu Jul 07 11:23:56 2022 +0200 @@ -0,0 +1,187 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2012 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> +# + +""" +Module implementing functions used by several IRC objects. +""" + +import re + +from PyQt6.QtCore import QTime, QCoreApplication +from PyQt6.QtWidgets import QApplication + +import Utilities +import Preferences + + +__UrlRe = re.compile( + r"""((?:http|ftp|https):\/\/[\w\-_]+(?:\.[\w\-_]+)+""" + r"""(?:[\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#])?)""") +__ColorRe = re.compile( + r"""((?:\x03(?:0[0-9]|1[0-5]|[0-9])?(?:,(?:0[0-9]|1[0-5]|[0-9]))?)""" + r"""|\x02|\x03|\x13|\x15|\x16|\x17|\x1d|\x1f)""") + + +def ircTimestamp(): + """ + Module method to generate a time stamp string. + + @return time stamp (string) + """ + if Preferences.getIrc("ShowTimestamps"): + if Preferences.getIrc("TimestampIncludeDate"): + if QApplication.isLeftToRight(): + f = "{0} {1}" + else: + f = "{1} {0}" + formatString = f.format(Preferences.getIrc("DateFormat"), + Preferences.getIrc("TimeFormat")) + else: + formatString = Preferences.getIrc("TimeFormat") + return '<font color="{0}">[{1}]</font> '.format( + Preferences.getIrc("TimestampColour"), + QTime.currentTime().toString(formatString)) + else: + return "" + + +def ircFilter(msg): + """ + Module method to make the message HTML compliant and detect URLs. + + @param msg message to process (string) + @return processed message (string) + """ + # step 1: cleanup message + msg = Utilities.html_encode(msg) + + # step 2: replace IRC formatting characters + openTags = [] + parts = __ColorRe.split(msg) + msgParts = [] + for part in parts: + if part == "\x02": # bold + if openTags and openTags[-1] == "b": + msgParts.append("</" + openTags.pop(-1) + ">") + else: + msgParts.append("<b>") + openTags.append("b") + elif part in ["\x03", "\x17"]: + if Preferences.getIrc("EnableIrcColours"): + if openTags and openTags[-1] == "span": + msgParts.append("</" + openTags.pop(-1) + ">") + else: + continue + else: + continue + elif part == "\x0f": # reset + while openTags: + msgParts.append("</" + openTags.pop(-1) + ">") + elif part == "\x13": # strikethru + if openTags and openTags[-1] == "s": + msgParts.append("</" + openTags.pop(-1) + ">") + else: + msgParts.append("<s>") + openTags.append("s") + elif part in ["\x15", "\x1f"]: # underline + if openTags and openTags[-1] == "u": + msgParts.append("</" + openTags.pop(-1) + ">") + else: + msgParts.append("<u>") + openTags.append("u") + elif part == "\x16": + # revert color not supported + continue + elif part == "\x1d": # italic + if openTags and openTags[-1] == "i": + msgParts.append("</" + openTags.pop(-1) + ">") + else: + msgParts.append("<i>") + openTags.append("i") + elif part.startswith("\x03"): + if Preferences.getIrc("EnableIrcColours"): + colors = part[1:].split(",", 1) + if len(colors) == 1: + # foreground color only + tag = '<span style="color:{0}">'.format(Preferences.getIrc( + "IrcColor{0}".format(int(colors[0])))) + else: + if colors[0]: + # foreground and background + tag = ( + '<span style="background-color:{0};color={1}">' + .format(Preferences.getIrc( + "IrcColor{0}".format(int(colors[0]))), + Preferences.getIrc( + "IrcColor{0}".format(int(colors[1])))) + ) + else: + # background only + tag = '<span style="background-color:{0}">'.format( + Preferences.getIrc( + "IrcColor{0}".format(int(colors[1])))) + msgParts.append(tag) + openTags.append("span") + else: + continue + else: + msgParts.append(part) + msg = "".join(msgParts) + + # step 3: find http and https links + parts = __UrlRe.split(msg) + msgParts = [] + for part in parts: + if part.startswith(("http://", "https://", "ftp://")): + msgParts.append('<a href="{0}" style="color:{1}">{0}</a>'.format( + part, Preferences.getIrc("HyperlinkColour"))) + else: + msgParts.append(part) + + return "".join(msgParts) + + +__channelModesDict = None + + +def __initChannelModesDict(): + """ + Private module function to initialize the channels modes dictionary. + """ + global __channelModesDict + + modesDict = { + "a": QCoreApplication.translate("IrcUtilities", "anonymous"), + "b": QCoreApplication.translate("IrcUtilities", "ban mask"), + "c": QCoreApplication.translate("IrcUtilities", "no colors allowed"), + "e": QCoreApplication.translate("IrcUtilities", "ban exception mask"), + "i": QCoreApplication.translate("IrcUtilities", "invite only"), + "k": QCoreApplication.translate("IrcUtilities", "password protected"), + "l": QCoreApplication.translate("IrcUtilities", "user limit"), + "m": QCoreApplication.translate("IrcUtilities", "moderated"), + "n": QCoreApplication.translate("IrcUtilities", + "no messages from outside"), + "p": QCoreApplication.translate("IrcUtilities", "private"), + "q": QCoreApplication.translate("IrcUtilities", "quiet"), + "r": QCoreApplication.translate("IrcUtilities", "reop channel"), + "s": QCoreApplication.translate("IrcUtilities", "secret"), + "t": QCoreApplication.translate("IrcUtilities", "topic protection"), + "I": QCoreApplication.translate("IrcUtilities", "invitation mask"), + } + __channelModesDict = modesDict + + +def getChannelModesDict(): + """ + Module function to get the dictionary with the channel modes mappings. + + @return dictionary with channel modes mapping (dict) + """ + global __channelModesDict + + if __channelModesDict is None: + __initChannelModesDict() + + return __channelModesDict