From 63633d428828a9670ea96b4612746463a4402967 Mon Sep 17 00:00:00 2001 From: Travis W Date: Mon, 30 Sep 2013 00:10:13 -0400 Subject: [PATCH 01/28] GumBot.git --- skype2irc.py | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/skype2irc.py b/skype2irc.py index 90578a0..488e614 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -33,23 +33,23 @@ from irclib import ServerNotConnectedError from threading import Timer -version = "0.2" +version = "0.22" servers = [ -("irc.freenode.net", 6667), -("hitchcock.freenode.net", 6667), -("leguin.freenode.net", 6667), -("verne.freenode.net", 6667), -("roddenberry.freenode.net", 6667), +("irc.someserver.net", 6667), ] -nick = "skype-}" -botname = "IRC ⟷ Skype".decode('UTF-8') +nick = "GumBot" +botname = "IRC ⟷ Skype Bot, codename GumBot".decode('UTF-8') password = None mirrors = { -'#test': -'X0_uprrk9XD40sCzSx_QtLT-oELEiV63Jw402jjG0dUaHiq2CD-F-6gKEQiFrgF_YPiUBcH-d6JcgmyWRPnteETG', +'#pfc': +'zx3SYBCX3Z3baXam0vsl9YDK8lYwBHNg9BtNoKW0GiILYibzfakNbW7hhbKyuwZtvFAKQbtrdp1YyXHmW-D0fm_4kw98nHW9Hu_r5h38R8JLLq_DrbT0W5O5d3Uf9nQlv0OLqlcPYpMzfc0Z7xDoUoE1yNCzFtDunqkbzOX0mGY-4ja9Cx_QXSgQGcYuhEw6cERQWyIVwQyjJ9fEg2s', +'#drawncon-staff': +'ySZLaBWTR_GxJ17cQAzOC7xZNVpedV09ycTm4jERs9GcZbL6MOPqqITnVUfdxRwEm2AykF86dRFwQS72KyKJdPmNDWf684Z0mYslSTYyH1DK-QwiI_5oTzA_ez1gmEpLHIZ0cFyx25DjnVhyvl1jDN2W1SGPrpIrAEHKXETKMhK__P2mrndwBaKC0lSp4Fbic74KdKVO5Z0Qezk0e56dDw', +'#funderdome': +'Yddl89U8KYP2qcW8pY6jKy13yOwloLEJlmXcLKKV9DHS6Vj2ITE_UV74aLFAwL1DFu160YGZCpxHYur6yi76UHYLHEmNT5T_iL8GBzMAAxGBu9oiAlbr_LLwn0QNjwSYekb6hab3Jf0iZ4hw_fLoj9O_zVafZOP1N8zHuSpg6Bs', } max_irc_msg_len = 442 @@ -63,9 +63,9 @@ preferred_encodings = ["UTF-8", "CP1252", "ISO-8859-1"] -name_start = "◀".decode('UTF-8') # "<" -name_end = "▶".decode('UTF-8') # ">" -emote_char = "✱".decode('UTF-8') # "*" +name_start = "<".decode('UTF-8') # "<" +name_end = ">".decode('UTF-8') # ">" +emote_char = "*".decode('UTF-8') # "*" muted_list_filename = nick + '.%s.muted' @@ -281,7 +281,8 @@ def on_welcome(self, connection, event): print "Connected to", self.connection.get_server_name() if password is not None: bot.say("NickServ", "identify " + password) - self.connection.add_global_handler("ctcp", self.handle_ctcp) + time.sleep(1) + self.connection.add_global_handler("ctcp", self.handle_ctcp) for pair in mirrors: connection.join(pair) print "Joined " + pair @@ -291,7 +292,7 @@ def on_pubmsg(self, connection, event): """React to channel messages""" args = event.arguments() source = event.source().split('!')[0] - target = event.target() + target = event.target().lower() cmds = args[0].split() if cmds[0].rstrip(":,") == nick: if len(cmds)==2: @@ -315,7 +316,7 @@ def handle_ctcp(self, connection, event): """Handle CTCP events for emoting""" args = event.arguments() source = event.source().split('!')[0] - target = event.target() + target = event.target().lower() if target in mirrors.keys(): if source in mutedl[target]: return From cdcf5abb1bd28aa41238f3cd5a7aae23c970186d Mon Sep 17 00:00:00 2001 From: xiagu Date: Tue, 1 Oct 2013 01:18:19 -0400 Subject: [PATCH 02/28] Extracted some of the more personal settings in skype2irc.py to a config file. A generic config file is provided. --- config.json | 9 +++++++++ skype2irc.py | 30 ++++++++++++++---------------- 2 files changed, 23 insertions(+), 16 deletions(-) create mode 100644 config.json diff --git a/config.json b/config.json new file mode 100644 index 0000000..1e04635 --- /dev/null +++ b/config.json @@ -0,0 +1,9 @@ +{ + "servers": [["irc.somenetwork.net", 6667]], + "nick": "GumBot", + "botname": "IRC <-> Skype Bot", + "password": "", + "mirrors": { + "#channel1": "blob" + } +} diff --git a/skype2irc.py b/skype2irc.py index 488e614..5308299 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -28,6 +28,7 @@ import sys, signal import time, datetime import string, textwrap +import json from ircbot import SingleServerIRCBot from irclib import ServerNotConnectedError @@ -35,22 +36,19 @@ version = "0.22" -servers = [ -("irc.someserver.net", 6667), -] - -nick = "GumBot" -botname = "IRC ⟷ Skype Bot, codename GumBot".decode('UTF-8') -password = None - -mirrors = { -'#pfc': -'zx3SYBCX3Z3baXam0vsl9YDK8lYwBHNg9BtNoKW0GiILYibzfakNbW7hhbKyuwZtvFAKQbtrdp1YyXHmW-D0fm_4kw98nHW9Hu_r5h38R8JLLq_DrbT0W5O5d3Uf9nQlv0OLqlcPYpMzfc0Z7xDoUoE1yNCzFtDunqkbzOX0mGY-4ja9Cx_QXSgQGcYuhEw6cERQWyIVwQyjJ9fEg2s', -'#drawncon-staff': -'ySZLaBWTR_GxJ17cQAzOC7xZNVpedV09ycTm4jERs9GcZbL6MOPqqITnVUfdxRwEm2AykF86dRFwQS72KyKJdPmNDWf684Z0mYslSTYyH1DK-QwiI_5oTzA_ez1gmEpLHIZ0cFyx25DjnVhyvl1jDN2W1SGPrpIrAEHKXETKMhK__P2mrndwBaKC0lSp4Fbic74KdKVO5Z0Qezk0e56dDw', -'#funderdome': -'Yddl89U8KYP2qcW8pY6jKy13yOwloLEJlmXcLKKV9DHS6Vj2ITE_UV74aLFAwL1DFu160YGZCpxHYur6yi76UHYLHEmNT5T_iL8GBzMAAxGBu9oiAlbr_LLwn0QNjwSYekb6hab3Jf0iZ4hw_fLoj9O_zVafZOP1N8zHuSpg6Bs', -} +# Read in from config file +configfile = open("config.json") +config = json.load(configfile) + +# servers = [(x[0], x[1]) for x in config['servers']] +servers = config['servers'] + +nick = config['nick'] +botname = config['botname'].decode("UTF-8") +password = config['password'] + +# {'#bronycon-registration': "skype:?chat&blob=DtK3LJ0-oziuQwXQaRQkMVAX2iNryb1VWY7kZAKjAOHRUgR_uFE3GEIncztciVRYGVRXEnEpGtqiS35jsld-cswmTP_RXyPEnsU0XLjwMLOKwcFjTJ1RNMcduvhlnFRlvUMZzr1HVH9gw45lfN0omAsoNOfwnvkgOIc1Ilh8Pcc6vc9TPrLy-QwAFvqdrNHqW6tpInYUpOMxaAS55L-JfKuOGbKbps3HVGU5MKBPFSIM"} +mirrors = config['mirrors'] max_irc_msg_len = 442 ping_interval = 2*60 From 3b3d6d9dd778ecec7a5dd6ba5f8a469b940e5e8e Mon Sep 17 00:00:00 2001 From: xiagu Date: Tue, 1 Oct 2013 01:35:42 -0400 Subject: [PATCH 03/28] Added basic vhost support (will tell HostServ to activate vhost if set to true) --- config.json | 1 + skype2irc.py | 3 +++ 2 files changed, 4 insertions(+) diff --git a/config.json b/config.json index 1e04635..79b428a 100644 --- a/config.json +++ b/config.json @@ -3,6 +3,7 @@ "nick": "GumBot", "botname": "IRC <-> Skype Bot", "password": "", + "vhost": false, "mirrors": { "#channel1": "blob" } diff --git a/skype2irc.py b/skype2irc.py index 5308299..527a032 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -46,6 +46,7 @@ nick = config['nick'] botname = config['botname'].decode("UTF-8") password = config['password'] +vhost = config['vhost'] # {'#bronycon-registration': "skype:?chat&blob=DtK3LJ0-oziuQwXQaRQkMVAX2iNryb1VWY7kZAKjAOHRUgR_uFE3GEIncztciVRYGVRXEnEpGtqiS35jsld-cswmTP_RXyPEnsU0XLjwMLOKwcFjTJ1RNMcduvhlnFRlvUMZzr1HVH9gw45lfN0omAsoNOfwnvkgOIc1Ilh8Pcc6vc9TPrLy-QwAFvqdrNHqW6tpInYUpOMxaAS55L-JfKuOGbKbps3HVGU5MKBPFSIM"} mirrors = config['mirrors'] @@ -279,6 +280,8 @@ def on_welcome(self, connection, event): print "Connected to", self.connection.get_server_name() if password is not None: bot.say("NickServ", "identify " + password) + if vhost: + bot.say("HostServ", "ON") time.sleep(1) self.connection.add_global_handler("ctcp", self.handle_ctcp) for pair in mirrors: From 351b2dd28381b4cc55660aea56d7a6f2587e9f63 Mon Sep 17 00:00:00 2001 From: xiagu Date: Tue, 1 Oct 2013 19:59:06 -0400 Subject: [PATCH 04/28] Updated README --- README.md | 6 +++--- skype2irc.py | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index af6fed3..9c1dc2f 100644 --- a/README.md +++ b/README.md @@ -24,13 +24,13 @@ For `python-skype` I used the version 1.0.31.0 provided at `ppa:skype-wrapper/pp CONFIGURE --------- -You can configure the IRC servers and Skype chatrooms to mirror in the header of `skype2irc.py`. You may define one IRC server and as many pairs of IRC channels and Skype chatrooms as you like. Skype chatrooms are defined by the blob, which you can obtain writing `/get uri` in a chatroom. +You can configure the IRC servers and Skype chatrooms to mirror in the configuration file `config.json`. You may define one IRC network (optionally with multiple servers) and as many pairs of IRC channels and Skype chatrooms as you like. Skype chatrooms are defined by the blob, which you can obtain writing `/get uri` in a chatroom. You may need to join your Skype chatroom to be mirrored before actually starting the gateway, because it seems that Skype API isn't always able to successfully join the chatroom using a blob provided (I usually get a timeout error). So make sure you have an access to chatroom using GUI before starting to hassle with the code. -The default values provided in the header of `skype2irc.py` should be enough to give the program a test run. +The default values provided should be enough to give the program a test run. -If you want to use an option to save broadcast states for IRC users, working directory for the script has to be writable. +If you want to use an option to save broadcast states for IRC users, the working directory for the script has to be writable. RUN --- diff --git a/skype2irc.py b/skype2irc.py index 527a032..06629e9 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -40,7 +40,6 @@ configfile = open("config.json") config = json.load(configfile) -# servers = [(x[0], x[1]) for x in config['servers']] servers = config['servers'] nick = config['nick'] @@ -48,7 +47,6 @@ password = config['password'] vhost = config['vhost'] -# {'#bronycon-registration': "skype:?chat&blob=DtK3LJ0-oziuQwXQaRQkMVAX2iNryb1VWY7kZAKjAOHRUgR_uFE3GEIncztciVRYGVRXEnEpGtqiS35jsld-cswmTP_RXyPEnsU0XLjwMLOKwcFjTJ1RNMcduvhlnFRlvUMZzr1HVH9gw45lfN0omAsoNOfwnvkgOIc1Ilh8Pcc6vc9TPrLy-QwAFvqdrNHqW6tpInYUpOMxaAS55L-JfKuOGbKbps3HVGU5MKBPFSIM"} mirrors = config['mirrors'] max_irc_msg_len = 442 From 410cedb71e6482bf81c586ef4055875fb95770d2 Mon Sep 17 00:00:00 2001 From: crystalllized Date: Wed, 2 Oct 2013 14:34:47 -0400 Subject: [PATCH 05/28] Update skype2irc.py Skype display name is now shown in IRC instead of Skype handle. --- skype2irc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skype2irc.py b/skype2irc.py index 06629e9..3eb5f40 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -177,9 +177,9 @@ def OnMessageStatus(Message, Status): if chat in usemap: if Status == 'RECEIVED': if msgtype == 'EMOTED': - bot.say(usemap[chat], emote_char + " " + senderHandle + " " + raw) + bot.say(usemap[chat], emote_char + " " + senderDisplay + " " + raw) elif msgtype == 'SAID': - bot.say(usemap[chat], name_start + senderHandle + name_end + " " + raw) + bot.say(usemap[chat], name_start + senderDisplay + name_end + " " + raw) def decode_irc(raw, preferred_encs = preferred_encodings): """Heuristic IRC charset decoder""" From a66e54b80330a0b6b53722e23d24dd19d4816a36 Mon Sep 17 00:00:00 2001 From: crystalllized Date: Wed, 2 Oct 2013 14:38:20 -0400 Subject: [PATCH 06/28] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 9c1dc2f..f69eb55 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ INSTALL On Ubuntu/Debian you need `python-irclib` and `python-skype` as well as Skype itself to run the script. +This bot runs with `python-irclib` 0.4.8. Newer versions may not have the necessary modules. + For `python-skype` I used the version 1.0.31.0 provided at `ppa:skype-wrapper/ppa`. Although newer version is packaged even for Ubuntu 11.04, this package didn't work out of the box on Ubuntu 12.04. CONFIGURE @@ -40,3 +42,5 @@ To run the gateway, Skype must be running and you must be logged in. You can do You can run `skype2irc.py` just from command line or use `ircbot.sh` to loop it. You can also run it from plain terminal providing the X desktop Skype will be started like `DISPLAY="host:0.0" ./skype2irc.py`. It could also make sense to run it using `ssh -X user@host` session or with something similar. + +On Mac OS X, ensure the bot is being run in 32-bit Python. 64-bit Python will result in segfaults. From 143923bd4c3fd196aafa46fa834dac44f60996a0 Mon Sep 17 00:00:00 2001 From: Jason Rosenman Date: Thu, 3 Oct 2013 14:09:01 -0400 Subject: [PATCH 07/28] Shows display name rather than handle. --- skype2irc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skype2irc.py b/skype2irc.py index 06629e9..3eb5f40 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -177,9 +177,9 @@ def OnMessageStatus(Message, Status): if chat in usemap: if Status == 'RECEIVED': if msgtype == 'EMOTED': - bot.say(usemap[chat], emote_char + " " + senderHandle + " " + raw) + bot.say(usemap[chat], emote_char + " " + senderDisplay + " " + raw) elif msgtype == 'SAID': - bot.say(usemap[chat], name_start + senderHandle + name_end + " " + raw) + bot.say(usemap[chat], name_start + senderDisplay + name_end + " " + raw) def decode_irc(raw, preferred_encs = preferred_encodings): """Heuristic IRC charset decoder""" From cb4e131b2d9f5457e4897d3f1b4a549ea3583058 Mon Sep 17 00:00:00 2001 From: Jason Rosenman Date: Mon, 7 Oct 2013 19:08:01 -0400 Subject: [PATCH 08/28] Bot now ignores unicode characters, instead of throwing an error. --- skype2irc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skype2irc.py b/skype2irc.py index 3eb5f40..0ea6514 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -177,9 +177,9 @@ def OnMessageStatus(Message, Status): if chat in usemap: if Status == 'RECEIVED': if msgtype == 'EMOTED': - bot.say(usemap[chat], emote_char + " " + senderDisplay + " " + raw) + bot.say(usemap[chat], emote_char + " " + senderDisplay.encode('ascii', 'ignore') + " " + raw.encode('ascii', 'ignore')) elif msgtype == 'SAID': - bot.say(usemap[chat], name_start + senderDisplay + name_end + " " + raw) + bot.say(usemap[chat], name_start + senderDisplay.encode('ascii', 'ignore') + name_end + " " + raw.encode('ascii', 'ignore')) def decode_irc(raw, preferred_encs = preferred_encodings): """Heuristic IRC charset decoder""" From ae0bb2036895958cc2942bd0794ef6774d74e690 Mon Sep 17 00:00:00 2001 From: xiagu Date: Thu, 10 Oct 2013 16:54:46 -0400 Subject: [PATCH 09/28] Merge pull request #2 from JRoTheGeek/master --- skype2irc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skype2irc.py b/skype2irc.py index 3eb5f40..0ea6514 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -177,9 +177,9 @@ def OnMessageStatus(Message, Status): if chat in usemap: if Status == 'RECEIVED': if msgtype == 'EMOTED': - bot.say(usemap[chat], emote_char + " " + senderDisplay + " " + raw) + bot.say(usemap[chat], emote_char + " " + senderDisplay.encode('ascii', 'ignore') + " " + raw.encode('ascii', 'ignore')) elif msgtype == 'SAID': - bot.say(usemap[chat], name_start + senderDisplay + name_end + " " + raw) + bot.say(usemap[chat], name_start + senderDisplay.encode('ascii', 'ignore') + name_end + " " + raw.encode('ascii', 'ignore')) def decode_irc(raw, preferred_encs = preferred_encodings): """Heuristic IRC charset decoder""" From 1a6c87a4a40c05e43fa0ccd8992d32d9f2e52ff0 Mon Sep 17 00:00:00 2001 From: xiagu Date: Wed, 30 Oct 2013 16:29:11 -0400 Subject: [PATCH 10/28] Fixed bug where IRCCloud's 'channel staff' pseduo-channels (ex. \!\@\%\#channel) would crash the bot. Now it just doesn't mirror them. --- skype2irc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skype2irc.py b/skype2irc.py index 0ea6514..2526b60 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -302,7 +302,7 @@ def on_pubmsg(self, connection, event): mutedl[target].append(source) save_mutes(target) return - if source in mutedl[target]: + if not mutedl.has_key(target) or source in mutedl[target]: return msg = name_start + source + name_end + " " for raw in args: From 1feedff02c50e3c89659a1a3abebfe50b7d743e5 Mon Sep 17 00:00:00 2001 From: Andrew Brockert Date: Wed, 13 Nov 2013 20:01:19 -0500 Subject: [PATCH 11/28] Fixed duplicate actions after bot has reconnected --- skype2irc.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/skype2irc.py b/skype2irc.py index 2526b60..ca1481b 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -281,6 +281,8 @@ def on_welcome(self, connection, event): if vhost: bot.say("HostServ", "ON") time.sleep(1) + # ensure handler is present exactly once by removing it before adding + self.connection.remove_global_handler("ctcp", self.handle_ctcp) self.connection.add_global_handler("ctcp", self.handle_ctcp) for pair in mirrors: connection.join(pair) From 2d8d1e575bfaeecc72927b4de12ba9bb2b90f965 Mon Sep 17 00:00:00 2001 From: Andrew Brockert Date: Mon, 25 Nov 2013 17:16:02 -0500 Subject: [PATCH 12/28] Added module support; a few minor fixes/tweaks --- config.json | 5 +++- example.py | 13 ++++++++++ quotes.py | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++ skype2irc.py | 58 +++++++++++++++++++++++++++++++---------- 4 files changed, 135 insertions(+), 14 deletions(-) create mode 100644 example.py create mode 100644 quotes.py diff --git a/config.json b/config.json index 79b428a..fbf1522 100644 --- a/config.json +++ b/config.json @@ -6,5 +6,8 @@ "vhost": false, "mirrors": { "#channel1": "blob" - } + }, + "modules": { + "example": {} + } } diff --git a/example.py b/example.py new file mode 100644 index 0000000..4a0c1b4 --- /dev/null +++ b/example.py @@ -0,0 +1,13 @@ +# example GumBot module + +config = None +usemap = None +ircbot = None + +def irc_msg(source, target, msg): + usemap[target].SendMessage('EXAMPLE: IRC msg %s -> %s: %s' % (source, target, msg)) + print 'EXAMPLE: IRC msg %s -> %s: %s' % (source, target, msg) + +def skype_msg(sourceDisplay, sourceHandle, target, msg): + ircbot.say(usemap[target], 'EXAMPLE: Skype msg %s (%s) -> %s: %s' % (sourceHandle, sourceDisplay, target, msg)) + print 'EXAMPLE: Skype msg %s (%s) -> %s: %s' % (sourceHandle, sourceDisplay, target, msg) diff --git a/quotes.py b/quotes.py new file mode 100644 index 0000000..4aacc12 --- /dev/null +++ b/quotes.py @@ -0,0 +1,73 @@ +# GumBot quotes module +# requires config keys: +# - url +# - http-user +# - http-pass + +import requests +import re + +def encode_utf8_to_iso88591(utf8_text): + # Borrowed from http://jamesmurty.com/2011/12/30/python-code-utf8-to-latin1/ + """ + Encode and return the given UTF-8 text as ISO-8859-1 (latin1) with + unsupported characters replaced by '?', except for common special + characters like smart quotes and symbols that we handle as well as we + can. + For example, the copyright symbol => '(c)' etc. + + If the given value is not a string it is returned unchanged. + + References: + + en.wikipedia.org/wiki/Quotation_mark_glyphs#Quotation_marks_in_Unicode + en.wikipedia.org/wiki/Copyright_symbol + en.wikipedia.org/wiki/Registered_trademark_symbol + en.wikipedia.org/wiki/Sound_recording_copyright_symbol + en.wikipedia.org/wiki/Service_mark_symbol + en.wikipedia.org/wiki/Trademark_symbol + """ + if not isinstance(utf8_text, basestring): + return utf8_text + # Replace "smart" and other single-quote like things + utf8_text = re.sub( + u'[\u02bc\u2018\u2019\u201a\u201b\u2039\u203a\u300c\u300d]', + "'", utf8_text) + # Replace "smart" and other double-quote like things + utf8_text = re.sub( + u'[\u00ab\u00bb\u201c\u201d\u201e\u201f\u300e\u300f]', + '"', utf8_text) + # Replace copyright symbol + utf8_text = re.sub(u'[\u00a9\u24b8\u24d2]', '(c)', utf8_text) + # Replace registered trademark symbol + utf8_text = re.sub(u'[\u00ae\u24c7]', '(r)', utf8_text) + # Replace sound recording copyright symbol + utf8_text = re.sub(u'[\u2117\u24c5\u24df]', '(p)', utf8_text) + # Replace service mark symbol + utf8_text = re.sub(u'[\u2120]', '(sm)', utf8_text) + # Replace trademark symbol + utf8_text = re.sub(u'[\u2122]', '(tm)', utf8_text) + # Replace/clobber any remaining UTF-8 characters that aren't in ISO-8859-1 + return utf8_text.encode('ISO-8859-1', 'replace') + +def irc_msg(source, target, msg): + if msg == '!quote': + r = requests.get(config['url'], auth=(config['http-user'], config['http-pass'])) + if r.status_code == 200: + quote = encode_utf8_to_iso88591(r.text) + ircbot.say(target, quote) + usemap[target].SendMessage(quote) + else: + ircbot.say(target, 'error getting quote :(') + usemap[target].SendMessage('error getting quote :(') + +def skype_msg(sourceDisplay, sourceHandle, target, msg): + if msg == '!quote': + r = requests.get(config['url'], auth=(config['http-user'], config['http-pass'])) + if r.status_code == 200: + quote = encode_utf8_to_iso88591(r.text) + ircbot.say(usemap[target], quote) + target.SendMessage(quote) + else: + ircbot.say(usemap[target], 'error getting quote :(') + target.SendMessage('error getting quote :(') diff --git a/skype2irc.py b/skype2irc.py index ca1481b..2189788 100755 --- a/skype2irc.py +++ b/skype2irc.py @@ -34,6 +34,13 @@ from irclib import ServerNotConnectedError from threading import Timer +import importlib +import logging + +logging.basicConfig(level=logging.WARN, + format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', + datefmt='%Y-%m-%d %H:%M:%S') + version = "0.22" # Read in from config file @@ -49,6 +56,8 @@ mirrors = config['mirrors'] +modconfig = config['modules'] + max_irc_msg_len = 442 ping_interval = 2*60 reconnect_interval = 30 @@ -180,6 +189,8 @@ def OnMessageStatus(Message, Status): bot.say(usemap[chat], emote_char + " " + senderDisplay.encode('ascii', 'ignore') + " " + raw.encode('ascii', 'ignore')) elif msgtype == 'SAID': bot.say(usemap[chat], name_start + senderDisplay.encode('ascii', 'ignore') + name_end + " " + raw.encode('ascii', 'ignore')) + for modname in modules: + modules[modname].skype_msg(senderHandle, senderDisplay, chat, raw) def decode_irc(raw, preferred_encs = preferred_encodings): """Heuristic IRC charset decoder""" @@ -218,7 +229,7 @@ class MirrorBot(SingleServerIRCBot): """Create IRC bot class""" def __init__(self): - SingleServerIRCBot.__init__(self, servers, nick, (botname + " " + topics).encode("UTF-8"), reconnect_interval) + SingleServerIRCBot.__init__(self, servers, nick, (botname).encode("UTF-8"), reconnect_interval) def start(self): """Override default start function to avoid starting/stalling the bot with no connection""" @@ -268,7 +279,7 @@ def say(self, target, msg, do_say = True): time.sleep(delay_btw_seqs) # to avoid flood excess except ServerNotConnectedError: print "{" +target + " " + msg+"} SKIPPED!" - + def notice(self, target, msg): """Send notices to channels/nicks""" self.say(self, target, msg, False) @@ -278,12 +289,12 @@ def on_welcome(self, connection, event): print "Connected to", self.connection.get_server_name() if password is not None: bot.say("NickServ", "identify " + password) - if vhost: - bot.say("HostServ", "ON") - time.sleep(1) - # ensure handler is present exactly once by removing it before adding - self.connection.remove_global_handler("ctcp", self.handle_ctcp) - self.connection.add_global_handler("ctcp", self.handle_ctcp) + if vhost: + bot.say("HostServ", "ON") + time.sleep(1) + # ensure handler is present exactly once by removing it before adding + self.connection.remove_global_handler("ctcp", self.handle_ctcp) + self.connection.add_global_handler("ctcp", self.handle_ctcp) for pair in mirrors: connection.join(pair) print "Joined " + pair @@ -306,12 +317,15 @@ def on_pubmsg(self, connection, event): return if not mutedl.has_key(target) or source in mutedl[target]: return - msg = name_start + source + name_end + " " + msg_hdr = name_start + source + name_end + " " + msg_body = '' for raw in args: - msg += decode_irc(raw) + "\n" - msg = msg.rstrip("\n") - print cut_title(usemap[target].FriendlyName), msg - usemap[target].SendMessage(msg) + msg_body += decode_irc(raw) + "\n" + msg_body = msg_body.rstrip("\n") + print cut_title(usemap[target].FriendlyName), msg_hdr + msg_body + usemap[target].SendMessage(msg_hdr + msg_body) + for modname in modules: + modules[modname].irc_msg(source, target, msg_body) def handle_ctcp(self, connection, event): """Handle CTCP events for emoting""" @@ -440,5 +454,23 @@ def on_privmsg(self, connection, event): load_mutes() bot = MirrorBot() + +# module API: +# main module sets config, usemap, and irc_say +# on Skype msg, main module calls module.skype_msg(senderDisplay, senderHandle, chat, msg) +# on IRC msg, main module calls module.irc_msg(source, target, msg) + +modules = {} +for modname in modconfig: + try: + module = importlib.import_module(modname) + module.config = modconfig[modname] + module.usemap = usemap + module.ircbot = bot + modules[modname] = module + logging.info('Loaded module %s' % modname) + except: + logging.error('Failed to load module %s!' % modname) + print "Starting IRC bot..." bot.start() From 907822696c973a690f8ad9bd5312773d65d11662 Mon Sep 17 00:00:00 2001 From: Andrew Brockert Date: Tue, 26 Nov 2013 12:41:53 -0500 Subject: [PATCH 13/28] Quotes module fixes and whitelist; config moved to .py --- config.json | 13 ------------- config.py | 16 ++++++++++++++++ ircbot.sh | 0 quotes.py | 34 ++++++++++++++++------------------ skype2irc.py | 6 ++---- 5 files changed, 34 insertions(+), 35 deletions(-) delete mode 100644 config.json create mode 100644 config.py mode change 100755 => 100644 ircbot.sh mode change 100755 => 100644 skype2irc.py diff --git a/config.json b/config.json deleted file mode 100644 index fbf1522..0000000 --- a/config.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "servers": [["irc.somenetwork.net", 6667]], - "nick": "GumBot", - "botname": "IRC <-> Skype Bot", - "password": "", - "vhost": false, - "mirrors": { - "#channel1": "blob" - }, - "modules": { - "example": {} - } -} diff --git a/config.py b/config.py new file mode 100644 index 0000000..a78291c --- /dev/null +++ b/config.py @@ -0,0 +1,16 @@ +# GumBot config file + +config = { + "servers": [("127.0.0.1", 6667)], + "nick": "GumBot", + "botname": "IRC <-> Skype Bot", + "password": "", + "vhost": False, + "mirrors": { + "#example": "blob" + }, + "modules": { +# "example": {}, +# "quotes": {"url": "", "http-user": "", "http-pass": "", "channels": ["#example"]}, + } +} diff --git a/ircbot.sh b/ircbot.sh old mode 100755 new mode 100644 diff --git a/quotes.py b/quotes.py index 4aacc12..1375e6c 100644 --- a/quotes.py +++ b/quotes.py @@ -50,24 +50,22 @@ def encode_utf8_to_iso88591(utf8_text): # Replace/clobber any remaining UTF-8 characters that aren't in ISO-8859-1 return utf8_text.encode('ISO-8859-1', 'replace') +def get_quote(): + try: + r = requests.get(config['url'], auth=(config['http-user'], config['http-pass']), timeout=3) + if r.status_code != 200: + raise Exception() + quote = encode_utf8_to_iso88591(r.content) + return quote + except Exception, e: + return 'error getting quote :( (%s)' % e + def irc_msg(source, target, msg): - if msg == '!quote': - r = requests.get(config['url'], auth=(config['http-user'], config['http-pass'])) - if r.status_code == 200: - quote = encode_utf8_to_iso88591(r.text) - ircbot.say(target, quote) - usemap[target].SendMessage(quote) - else: - ircbot.say(target, 'error getting quote :(') - usemap[target].SendMessage('error getting quote :(') + if msg == '!quote' and target in config['channels']: + ircbot.say(target, get_quote()) + usemap[target].SendMessage(get_quote()) def skype_msg(sourceDisplay, sourceHandle, target, msg): - if msg == '!quote': - r = requests.get(config['url'], auth=(config['http-user'], config['http-pass'])) - if r.status_code == 200: - quote = encode_utf8_to_iso88591(r.text) - ircbot.say(usemap[target], quote) - target.SendMessage(quote) - else: - ircbot.say(usemap[target], 'error getting quote :(') - target.SendMessage('error getting quote :(') + if msg == '!quote' and usemap[target] in config['channels']: + ircbot.say(usemap[target], get_quote()) + target.SendMessage(get_quote()) diff --git a/skype2irc.py b/skype2irc.py old mode 100755 new mode 100644 index 2189788..b2408b9 --- a/skype2irc.py +++ b/skype2irc.py @@ -34,6 +34,8 @@ from irclib import ServerNotConnectedError from threading import Timer +from config import config + import importlib import logging @@ -43,10 +45,6 @@ version = "0.22" -# Read in from config file -configfile = open("config.json") -config = json.load(configfile) - servers = config['servers'] nick = config['nick'] From 9bbdcaaf25d4215cdaa41864e57b5d27fd5d344d Mon Sep 17 00:00:00 2001 From: Andrew Brockert Date: Tue, 26 Nov 2013 13:57:50 -0500 Subject: [PATCH 14/28] FUCK CHARACTER ENCODINGS. Also fixed some derpiness. --- quotes.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/quotes.py b/quotes.py index 1375e6c..8a19524 100644 --- a/quotes.py +++ b/quotes.py @@ -6,6 +6,7 @@ import requests import re +import traceback def encode_utf8_to_iso88591(utf8_text): # Borrowed from http://jamesmurty.com/2011/12/30/python-code-utf8-to-latin1/ @@ -31,11 +32,11 @@ def encode_utf8_to_iso88591(utf8_text): return utf8_text # Replace "smart" and other single-quote like things utf8_text = re.sub( - u'[\u02bc\u2018\u2019\u201a\u201b\u2039\u203a\u300c\u300d]', + u'[\u02bc\u2018\u2019\u201a\u201b\u2039\u203a\u300c\u300d\x91\x92]', "'", utf8_text) # Replace "smart" and other double-quote like things utf8_text = re.sub( - u'[\u00ab\u00bb\u201c\u201d\u201e\u201f\u300e\u300f]', + u'[\u00ab\u00bb\u201c\u201d\u201e\u201f\u300e\u300f\x93\x94]', '"', utf8_text) # Replace copyright symbol utf8_text = re.sub(u'[\u00a9\u24b8\u24d2]', '(c)', utf8_text) @@ -55,17 +56,21 @@ def get_quote(): r = requests.get(config['url'], auth=(config['http-user'], config['http-pass']), timeout=3) if r.status_code != 200: raise Exception() - quote = encode_utf8_to_iso88591(r.content) + # FUCK CHARACTER ENCODINGS. + quote = encode_utf8_to_iso88591(r.content.decode('ISO-8859-1')) return quote except Exception, e: + traceback.print_exc() return 'error getting quote :( (%s)' % e def irc_msg(source, target, msg): if msg == '!quote' and target in config['channels']: - ircbot.say(target, get_quote()) - usemap[target].SendMessage(get_quote()) + quote = get_quote() + ircbot.say(target, quote) + usemap[target].SendMessage(quote) def skype_msg(sourceDisplay, sourceHandle, target, msg): if msg == '!quote' and usemap[target] in config['channels']: - ircbot.say(usemap[target], get_quote()) - target.SendMessage(get_quote()) + quote = get_quote() + ircbot.say(usemap[target], quote) + target.SendMessage(quote) From 71b81fbf3572b33aa852ba620e925ed79544d314 Mon Sep 17 00:00:00 2001 From: Andrew Brockert Date: Thu, 30 Jan 2014 18:02:48 -0500 Subject: [PATCH 15/28] Removed "topics" display; fixed crash on /msg'd actions --- skype2irc.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/skype2irc.py b/skype2irc.py index b2408b9..3096ff4 100644 --- a/skype2irc.py +++ b/skype2irc.py @@ -73,8 +73,6 @@ muted_list_filename = nick + '.%s.muted' -topics = "" - usemap = {} bot = None mutedl = {} @@ -333,7 +331,7 @@ def handle_ctcp(self, connection, event): if target in mirrors.keys(): if source in mutedl[target]: return - if args[0]=='ACTION' and len(args) == 2: + if args[0]=='ACTION' and len(args) == 2 and target in usemap: # An emote/action message has been sent to us msg = emote_char + " " + source + " " + decode_irc(args[1]) + "\n" print cut_title(usemap[target].FriendlyName), msg @@ -402,7 +400,7 @@ def on_privmsg(self, connection, event): bot.say(source, msg) elif two in ('?', 'HE', 'HI', 'WT'): # HELP - bot.say(source, botname + " " + version + " " + topics + "\n * ON/OFF/STATUS --- Trigger mirroring to Skype\n * INFO #channel --- Display list of users from relevant Skype chat\nDetails: https://github.com/boamaod/skype2irc#readme") + bot.say(source, botname + " " + version + " " + "\n * ON/OFF/STATUS --- Trigger mirroring to Skype\n * INFO #channel --- Display list of users from relevant Skype chat\nDetails: https://github.com/boamaod/skype2irc#readme") # *** Start everything up! *** @@ -439,15 +437,12 @@ def on_privmsg(self, connection, event): print 'Skype API initialised.' -topics = "[" for pair in mirrors: chat = skype.CreateChatUsingBlob(mirrors[pair]) topic = chat.FriendlyName print "Joined \"" + topic + "\"" - topics += cut_title(topic) + "|" usemap[pair] = chat usemap[chat] = pair -topics = topics.rstrip("|") + "]" load_mutes() From 3219062c5df70eb3f9d2e0770ab06627ca08562b Mon Sep 17 00:00:00 2001 From: Andrew Brockert Date: Thu, 30 Jan 2014 18:50:18 -0500 Subject: [PATCH 16/28] added karma module (with contributions from Sheva) --- karma.py | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 karma.py diff --git a/karma.py b/karma.py new file mode 100644 index 0000000..44177c9 --- /dev/null +++ b/karma.py @@ -0,0 +1,100 @@ +import re +import sqlite3 +import datetime + +conn = sqlite3.connect('karma.db') +cur = conn.cursor() + +try: + cur.execute('''CREATE TABLE "karma" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "name" TEXT NOT NULL COLLATE NOCASE, + "delta" INTEGER, + "comment" TEXT, + "add_time" TEXT NOT NULL + );''') + conn.commit() +except sqlite3.OperationalError: + pass + +config = None +usemap = None +ircbot = None + +exp = re.compile("^(\([^)]+\)|[^ ]+)([+]{2}|[-]{2})(.*)$") + +def getsubject(msg): + msg = msg.strip().lower() + if msg[0] == '(' and msg[len(msg) - 1] == ')': + msg = msg[0:len(msg)-1].strip() + return msg + +def getreason(msg, sender): + msg = msg.strip() + if msg.startswith('#'): + return msg[1:].strip() + elif msg.startswith('//'): + return msg[2:].strip() + else: + return '' + +def karmaparse(source, msg): + msg = msg.strip() + ismatch = exp.match(msg) + if ismatch: + subject = getsubject(ismatch.group(1)) + amount = ismatch.group(2) + if amount == '--': + amount = -1 + ktype = 'negative' + else: + amount = 1 + ktype = 'positive' + reason = getreason(ismatch.group(3), source) + if reason: + reason = ' for "%s"' % reason + if subject == source.lower() and amount > 0: + return "You can't give karma to yourself... loser." + else: + cur.execute('''INSERT INTO karma (`name`,`delta`,`comment`,`add_time`) VALUES (?,?,?,?)''', (subject, amount, reason, datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'))) + conn.commit() + return "%s gave %s %s karma%s." % (source, subject, ktype, reason) + else: + return None + +def get_karma(msg): + m = re.match('!karma (.+)', msg) + if not m: + return + ktgt = m.group(1).strip() + cur.execute('''SELECT SUM(`delta`) FROM karma WHERE `name` LIKE ?;''', (ktgt,)) + ksum = cur.fetchone()[0] + if ksum is None: + kstr = 'No karma recorded for %s.' % ktgt + else: + kstr = 'Current karma for %s is %s.' % (ktgt, ksum) + return kstr + +def irc_msg(source, target, msg): + if not target in config['channels']: + return + if msg.startswith('!karma'): + kstr = get_karma(msg) + ircbot.say(target, kstr) + usemap[target].SendMessage(kstr) + else: + karma = karmaparse(source, msg) + if karma and target in config['channels']: + ircbot.say(target, karma) + usemap[target].SendMessage(karma) + +def skype_msg(sourceDisplay, sourceHandle, target, msg): + if msg.startswith('!karma'): + kstr = get_karma(msg) + ircbot.say(usemap[target], kstr) + target.SendMessage(kstr) + else: + karma = karmaparse(sourceDisplay, msg) + if karma and usemap[target] in config['channels']: + ircbot.say(usemap[target], karma) + target.SendMessage(karma) From 33ccfbed54b0895ac729becea0d817a4d76f360d Mon Sep 17 00:00:00 2001 From: Batsheva Date: Sun, 2 Feb 2014 03:12:52 +0200 Subject: [PATCH 17/28] Added message scanner module. --- message_scanner.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 message_scanner.py diff --git a/message_scanner.py b/message_scanner.py new file mode 100644 index 0000000..77dae39 --- /dev/null +++ b/message_scanner.py @@ -0,0 +1,35 @@ +#Bot will auto-respond to lines containing a specified regex +#I <3 PR + +import re + +config = None +usemap = None +ircbot = None + +#put the regex you want here +my_exp = re.compile('') + +#put the message to auto-respond with here +#suggestion: "Just ignore her." +my_response = '' + +def message_scan(source, msg): + msg = msg.strip() + ismatch = my_exp.match(msg) + if ismatch: + return source + ": " + my_response + +def irc_msg(source, target, msg): + if not target in config['channels']: + return + scanner = message_scan(source, msg) + if scanner and target in config['channels']: + ircbot.say(target, scanner) + usemap[target].SendMessage(scanner) + +def skype_msg(sourceDisplay, sourceHandle, target, msg): + scanner = message_scan(sourceDisplay, msg) + if scanner and usemap[target] in config['channels']: + ircbot.say(usemap[target], scanner) + target.SendMessage(scanner) \ No newline at end of file From 7b08d0329a43a3c3fc0af115cb026ed7881b7667 Mon Sep 17 00:00:00 2001 From: Sheva Date: Sun, 2 Feb 2014 03:31:46 +0200 Subject: [PATCH 18/28] Renamed message_scanner.py to something more sensible (auto_reply.py). --- auto_reply.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 auto_reply.py diff --git a/auto_reply.py b/auto_reply.py new file mode 100644 index 0000000..77dae39 --- /dev/null +++ b/auto_reply.py @@ -0,0 +1,35 @@ +#Bot will auto-respond to lines containing a specified regex +#I <3 PR + +import re + +config = None +usemap = None +ircbot = None + +#put the regex you want here +my_exp = re.compile('') + +#put the message to auto-respond with here +#suggestion: "Just ignore her." +my_response = '' + +def message_scan(source, msg): + msg = msg.strip() + ismatch = my_exp.match(msg) + if ismatch: + return source + ": " + my_response + +def irc_msg(source, target, msg): + if not target in config['channels']: + return + scanner = message_scan(source, msg) + if scanner and target in config['channels']: + ircbot.say(target, scanner) + usemap[target].SendMessage(scanner) + +def skype_msg(sourceDisplay, sourceHandle, target, msg): + scanner = message_scan(sourceDisplay, msg) + if scanner and usemap[target] in config['channels']: + ircbot.say(usemap[target], scanner) + target.SendMessage(scanner) \ No newline at end of file From 9bca0359013463e42e0b4d908774459d674ecc8c Mon Sep 17 00:00:00 2001 From: Sheva Das Date: Sun, 2 Feb 2014 03:33:37 +0200 Subject: [PATCH 19/28] Delete message_scanner.py --- message_scanner.py | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 message_scanner.py diff --git a/message_scanner.py b/message_scanner.py deleted file mode 100644 index 77dae39..0000000 --- a/message_scanner.py +++ /dev/null @@ -1,35 +0,0 @@ -#Bot will auto-respond to lines containing a specified regex -#I <3 PR - -import re - -config = None -usemap = None -ircbot = None - -#put the regex you want here -my_exp = re.compile('') - -#put the message to auto-respond with here -#suggestion: "Just ignore her." -my_response = '' - -def message_scan(source, msg): - msg = msg.strip() - ismatch = my_exp.match(msg) - if ismatch: - return source + ": " + my_response - -def irc_msg(source, target, msg): - if not target in config['channels']: - return - scanner = message_scan(source, msg) - if scanner and target in config['channels']: - ircbot.say(target, scanner) - usemap[target].SendMessage(scanner) - -def skype_msg(sourceDisplay, sourceHandle, target, msg): - scanner = message_scan(sourceDisplay, msg) - if scanner and usemap[target] in config['channels']: - ircbot.say(usemap[target], scanner) - target.SendMessage(scanner) \ No newline at end of file From af4b6b77cf521bc659d0b23974bdd7e88e70fd98 Mon Sep 17 00:00:00 2001 From: Andrew Brockert Date: Tue, 11 Feb 2014 13:48:11 -0500 Subject: [PATCH 20/28] fixed crashbug upon receiving a line containing only spaces on IRC --- skype2irc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/skype2irc.py b/skype2irc.py index 3096ff4..41cda2b 100644 --- a/skype2irc.py +++ b/skype2irc.py @@ -302,7 +302,7 @@ def on_pubmsg(self, connection, event): source = event.source().split('!')[0] target = event.target().lower() cmds = args[0].split() - if cmds[0].rstrip(":,") == nick: + if cmds and cmds[0].rstrip(":,") == nick: if len(cmds)==2: if cmds[1].upper() == 'ON' and source in mutedl[target]: mutedl[target].remove(source) @@ -342,6 +342,8 @@ def on_privmsg(self, connection, event): source = event.source().split('!')[0] raw = event.arguments()[0].decode('utf-8', 'ignore') args = raw.split() + if not args: + return two = args[0][:2].upper() if two == 'ST': # STATUS From a665e9b17a555056705ee7909628697e71672397 Mon Sep 17 00:00:00 2001 From: Andrew Brockert Date: Sat, 5 Apr 2014 11:50:45 -0400 Subject: [PATCH 21/28] Print exception when a module fails to load; add utility scripts; minor README update --- README.md | 3 +++ ircbot_once.sh | 3 +++ killbot.sh | 3 +++ skype2irc.py | 6 ++++-- 4 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 ircbot_once.sh create mode 100644 killbot.sh diff --git a/README.md b/README.md index f69eb55..041e170 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,9 @@ This bot runs with `python-irclib` 0.4.8. Newer versions may not have the necess For `python-skype` I used the version 1.0.31.0 provided at `ppa:skype-wrapper/ppa`. Although newer version is packaged even for Ubuntu 11.04, this package didn't work out of the box on Ubuntu 12.04. +Module deps: +* quotes and addquote require python-requests + CONFIGURE --------- diff --git a/ircbot_once.sh b/ircbot_once.sh new file mode 100644 index 0000000..f016e9d --- /dev/null +++ b/ircbot_once.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +DISPLAY="host:0.0" python skype2irc.py diff --git a/killbot.sh b/killbot.sh new file mode 100644 index 0000000..08a4efe --- /dev/null +++ b/killbot.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +kill `ps aux | grep skype2irc | grep -v grep | awk '{print $2;}'` diff --git a/skype2irc.py b/skype2irc.py index 41cda2b..a1aae4f 100644 --- a/skype2irc.py +++ b/skype2irc.py @@ -38,6 +38,7 @@ import importlib import logging +import traceback logging.basicConfig(level=logging.WARN, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s', @@ -464,8 +465,9 @@ def on_privmsg(self, connection, event): module.ircbot = bot modules[modname] = module logging.info('Loaded module %s' % modname) - except: - logging.error('Failed to load module %s!' % modname) + except Exception, exc: + logging.error('Failed to load module %s! Exception follows:' % modname) + traceback.print_exc() print "Starting IRC bot..." bot.start() From f38a4a6948afbf1444ef40adb857579a5ea6e0ea Mon Sep 17 00:00:00 2001 From: Sheva Date: Sun, 6 Apr 2014 14:41:49 +0300 Subject: [PATCH 22/28] Now with 50% less silliness. --- karma.py | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/karma.py b/karma.py index 44177c9..e6ef285 100644 --- a/karma.py +++ b/karma.py @@ -38,6 +38,11 @@ def getreason(msg, sender): else: return '' +def fetch_karma(ktgt): + cur.execute('''SELECT SUM(`delta`) FROM karma WHERE `name` LIKE ?;''', (ktgt,)) + ksum = cur.fetchone()[0] + return ksum + def karmaparse(source, msg): msg = msg.strip() ismatch = exp.match(msg) @@ -55,10 +60,15 @@ def karmaparse(source, msg): reason = ' for "%s"' % reason if subject == source.lower() and amount > 0: return "You can't give karma to yourself... loser." - else: + else: cur.execute('''INSERT INTO karma (`name`,`delta`,`comment`,`add_time`) VALUES (?,?,?,?)''', (subject, amount, reason, datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'))) conn.commit() - return "%s gave %s %s karma%s." % (source, subject, ktype, reason) + if subject == config['nick'].lower() and amount > 0: + return "Karma for %s is now %s. Thanks, %s!" % (subject, fetch_karma(subject), source) + elif subject == config['nick'].lower() and amount < 0: + return "Karma for %s is now %s. Pfft." % (subject, fetch_karma(subject)) + else: + return "Karma for %s is now %s." % (subject, fetch_karma(subject)) else: return None @@ -67,14 +77,24 @@ def get_karma(msg): if not m: return ktgt = m.group(1).strip() - cur.execute('''SELECT SUM(`delta`) FROM karma WHERE `name` LIKE ?;''', (ktgt,)) - ksum = cur.fetchone()[0] + ksum = fetch_karma(ktgt) if ksum is None: - kstr = 'No karma recorded for %s.' % ktgt + kstr = 'No karma has ever been assigned to %s.' % ktgt else: - kstr = 'Current karma for %s is %s.' % (ktgt, ksum) + kstr = '%s has %s karma.' % (ktgt, ksum) return kstr + +""" +def explain(msg): + m = re.match('!explain (.+)', msg) + if not m: + return + ktgt = m.group(1).strip() + cur.execute('''SELECT comment FROM karma where `name` LIKE ?;''', (ktgt,)) +""" + + def irc_msg(source, target, msg): if not target in config['channels']: return From 484f8c197a7c92fab2529da5c36a8be0d2c15a73 Mon Sep 17 00:00:00 2001 From: Andrew Brockert Date: Sat, 3 May 2014 14:24:56 -0400 Subject: [PATCH 23/28] Fixed SQLite threading error in karma --- karma.py | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/karma.py b/karma.py index e6ef285..c4a7810 100644 --- a/karma.py +++ b/karma.py @@ -2,20 +2,19 @@ import sqlite3 import datetime -conn = sqlite3.connect('karma.db') -cur = conn.cursor() - -try: - cur.execute('''CREATE TABLE "karma" ( - "id" INTEGER PRIMARY KEY AUTOINCREMENT, - "name" TEXT NOT NULL COLLATE NOCASE, - "delta" INTEGER, - "comment" TEXT, - "add_time" TEXT NOT NULL - );''') - conn.commit() -except sqlite3.OperationalError: - pass +with sqlite3.connect('karma.db') as conn: + cur = conn.cursor() + try: + cur.execute('''CREATE TABLE "karma" ( + "id" INTEGER PRIMARY KEY AUTOINCREMENT, + "name" TEXT NOT NULL COLLATE NOCASE, + "delta" INTEGER, + "comment" TEXT, + "add_time" TEXT NOT NULL + );''') + conn.commit() + except sqlite3.OperationalError: + pass config = None usemap = None @@ -39,8 +38,10 @@ def getreason(msg, sender): return '' def fetch_karma(ktgt): - cur.execute('''SELECT SUM(`delta`) FROM karma WHERE `name` LIKE ?;''', (ktgt,)) - ksum = cur.fetchone()[0] + with sqlite3.connect('karma.db') as conn: + cur = conn.cursor() + cur.execute('''SELECT SUM(`delta`) FROM karma WHERE `name` LIKE ?;''', (ktgt,)) + ksum = cur.fetchone()[0] return ksum def karmaparse(source, msg): @@ -61,8 +62,10 @@ def karmaparse(source, msg): if subject == source.lower() and amount > 0: return "You can't give karma to yourself... loser." else: - cur.execute('''INSERT INTO karma (`name`,`delta`,`comment`,`add_time`) VALUES (?,?,?,?)''', (subject, amount, reason, datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'))) - conn.commit() + with sqlite3.connect('karma.db') as conn: + cur = conn.cursor() + cur.execute('''INSERT INTO karma (`name`,`delta`,`comment`,`add_time`) VALUES (?,?,?,?)''', (subject, amount, reason, datetime.datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'))) + conn.commit() if subject == config['nick'].lower() and amount > 0: return "Karma for %s is now %s. Thanks, %s!" % (subject, fetch_karma(subject), source) elif subject == config['nick'].lower() and amount < 0: From 8774257c85493066cffcb70f3371d52b672c1fb4 Mon Sep 17 00:00:00 2001 From: Xiagu Date: Thu, 29 May 2014 18:43:05 -0400 Subject: [PATCH 24/28] Changed config.py to config.py.default to not conflict with users' own configs --- config.py => config.py.default | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename config.py => config.py.default (100%) diff --git a/config.py b/config.py.default similarity index 100% rename from config.py rename to config.py.default From 507acfe76c3f700d3f7388dec7c2a4d0c28cdabc Mon Sep 17 00:00:00 2001 From: anrodger Date: Sun, 3 Jan 2016 17:08:08 -0500 Subject: [PATCH 25/28] Strip mIRC color codes from messages The ^C/\x03 control character was already stripped, but not the foreground and background colors after it. --- skype2irc.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/skype2irc.py b/skype2irc.py index a1aae4f..6b2295a 100644 --- a/skype2irc.py +++ b/skype2irc.py @@ -28,6 +28,7 @@ import sys, signal import time, datetime import string, textwrap +import re import json from ircbot import SingleServerIRCBot @@ -256,6 +257,8 @@ def on_pong(self, connection, event): def say(self, target, msg, do_say = True): """Send messages to channels/nicks""" try: + # Strip mIRC color codes (\x03XX,YY) from the message + msg = re.sub(r"\x03\d+(,\d+)?", "", msg) lines = msg.encode("UTF-8").split("\n") cur = 0 for line in lines: From 556432315f1e85576aec29d54fc0fd9e0c852f5f Mon Sep 17 00:00:00 2001 From: anrodger Date: Sun, 3 Jan 2016 17:34:04 -0500 Subject: [PATCH 26/28] Removed trailing spaces --- skype2irc.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/skype2irc.py b/skype2irc.py index 6b2295a..5a0f2e5 100644 --- a/skype2irc.py +++ b/skype2irc.py @@ -13,7 +13,7 @@ # 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 . @@ -98,37 +98,37 @@ def get_relative_time(dt): now = datetime.datetime.now() delta_time = now - dt - delta = delta_time.days * DAY + delta_time.seconds + delta = delta_time.days * DAY + delta_time.seconds minutes = delta / MINUTE hours = delta / HOUR days = delta / DAY if delta <= 0: return "in the future" - if delta < 1 * MINUTE: + if delta < 1 * MINUTE: if delta == 1: return "moment ago" else: return str(delta) + " seconds ago" - if delta < 2 * MINUTE: + if delta < 2 * MINUTE: return "a minute ago" - if delta < 45 * MINUTE: + if delta < 45 * MINUTE: return str(minutes) + " minutes ago" - if delta < 90 * MINUTE: + if delta < 90 * MINUTE: return "an hour ago" if delta < 24 * HOUR: return str(hours) + " hours ago" - if delta < 48 * HOUR: + if delta < 48 * HOUR: return "yesterday" - if delta < 30 * DAY: + if delta < 30 * DAY: return str(days) + " days ago" - if delta < 12 * MONTH: + if delta < 12 * MONTH: months = delta / MONTH if months <= 1: return "one month ago" else: return str(months) + " months ago" - else: + else: years = days / 365.0 if years <= 1: return "one year ago" @@ -279,7 +279,7 @@ def say(self, target, msg, do_say = True): time.sleep(delay_btw_seqs) # to avoid flood excess except ServerNotConnectedError: print "{" +target + " " + msg+"} SKIPPED!" - + def notice(self, target, msg): """Send notices to channels/nicks""" self.say(self, target, msg, False) @@ -349,7 +349,7 @@ def on_privmsg(self, connection, event): if not args: return two = args[0][:2].upper() - + if two == 'ST': # STATUS muteds = [] brdcsts = [] @@ -362,21 +362,21 @@ def on_privmsg(self, connection, event): bot.say(source, "You're mirrored to Skype from " + ", ".join(brdcsts)) if len(muteds) > 0: bot.say(source, "You're silent to Skype on " + ", ".join(muteds)) - + if two == 'OF': # OFF for channel in mirrors.keys(): if source not in mutedl[channel]: mutedl[channel].append(source) save_mutes(channel) bot.say(source, "You're silent to Skype now") - + elif two == 'ON': # ON for channel in mirrors.keys(): if source in mutedl[channel]: mutedl[channel].remove(source) save_mutes(channel) bot.say(source, "You're mirrored to Skype now") - + elif two == 'IN' and len(args) > 1 and args[1] in mirrors: # INFO chat = usemap[args[1]] members = chat.Members @@ -404,7 +404,7 @@ def on_privmsg(self, connection, event): msg += desc + '\n' msg = msg.rstrip("\n") bot.say(source, msg) - + elif two in ('?', 'HE', 'HI', 'WT'): # HELP bot.say(source, botname + " " + version + " " + "\n * ON/OFF/STATUS --- Trigger mirroring to Skype\n * INFO #channel --- Display list of users from relevant Skype chat\nDetails: https://github.com/boamaod/skype2irc#readme") From 4a883e71cb4be773cb1ba6fbe267966650e019fb Mon Sep 17 00:00:00 2001 From: anrodger Date: Sun, 3 Jan 2016 17:34:20 -0500 Subject: [PATCH 27/28] Fix stripping color codes to be on decode Multiple places use the decode_irc method to get their msg text. This is a sign of another problem, in that there shouldn't be separate code for sending messages for modules and the "default", but this is a simple fix to strip color codes from all text from IRC. --- skype2irc.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/skype2irc.py b/skype2irc.py index 5a0f2e5..e86529a 100644 --- a/skype2irc.py +++ b/skype2irc.py @@ -208,7 +208,9 @@ def decode_irc(raw, preferred_encs = preferred_encodings): except: res = raw.decode(enc, 'ignore') #enc += "+IGNORE" - return res + # Strip mIRC color codes (\x03XX,YY) from the message + stripped = re.sub(r"\x03\d+(,\d+)?", "", res) + return stripped def signal_handler(signal, frame): print "Ctrl+C pressed!" @@ -257,8 +259,6 @@ def on_pong(self, connection, event): def say(self, target, msg, do_say = True): """Send messages to channels/nicks""" try: - # Strip mIRC color codes (\x03XX,YY) from the message - msg = re.sub(r"\x03\d+(,\d+)?", "", msg) lines = msg.encode("UTF-8").split("\n") cur = 0 for line in lines: From 457871c02d6bf8737ac607f256ea4394e2f2f615 Mon Sep 17 00:00:00 2001 From: anrodger Date: Sun, 3 Jan 2016 17:40:03 -0500 Subject: [PATCH 28/28] Fix bug with too-greedy stripping regexp Only remove up to 2 digits for each. --- skype2irc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skype2irc.py b/skype2irc.py index e86529a..39f0e52 100644 --- a/skype2irc.py +++ b/skype2irc.py @@ -209,7 +209,7 @@ def decode_irc(raw, preferred_encs = preferred_encodings): res = raw.decode(enc, 'ignore') #enc += "+IGNORE" # Strip mIRC color codes (\x03XX,YY) from the message - stripped = re.sub(r"\x03\d+(,\d+)?", "", res) + stripped = re.sub(r"\x03\d{1,2}(,\d{1,2})?", "", res) return stripped def signal_handler(signal, frame):