From 60f47b04174d016cc86c6e06fdaf0794c3d14216 Mon Sep 17 00:00:00 2001 From: Simeon Simeonov Date: Wed, 7 May 2014 22:28:48 +0200 Subject: Git server / generic client and weechat client completed --- beinc_generic_client.py | 158 ++++++++++++++++++++++ beinc_server.json | 25 ++-- beinc_server.py | 148 +++++++++++---------- beinc_weechat.py | 331 +++++++++++++++++++++++++++++++++++++---------- bosd.py | 101 --------------- bpynotify_orm.py | 32 ----- socket_server.py | 77 ----------- web_server.py | 47 ------- weechat_notify.py | 49 ------- weechat_notify_server.py | 116 ----------------- 10 files changed, 509 insertions(+), 575 deletions(-) create mode 100755 beinc_generic_client.py delete mode 100644 bosd.py delete mode 100644 bpynotify_orm.py delete mode 100755 socket_server.py delete mode 100755 web_server.py delete mode 100755 weechat_notify.py delete mode 100755 weechat_notify_server.py diff --git a/beinc_generic_client.py b/beinc_generic_client.py new file mode 100755 index 0000000..6cffc84 --- /dev/null +++ b/beinc_generic_client.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Blackmore's Enhanced IRC-Notification Collection (BEINC) v1.0 +# Copyright (C) 2013-2014 Simeon Simeonov + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + +import argparse +import errno +import getpass +import httplib +import socket +import ssl +import sys +import urllib +import urllib2 + + +__author__ = 'Simeon Simeonov' +__version__ = '1.0' +__license__ = 'GPL3' + + +class ValidHTTPSConnection(httplib.HTTPConnection): + """ + Implements a simple CERT verification functionality + """ + + default_port = httplib.HTTPS_PORT + + def __init__(self, *args, **kwargs): + httplib.HTTPConnection.__init__(self, *args, **kwargs) + + def connect(self): + sock = socket.create_connection((self.host, self.port), + self.timeout, self.source_address) + if self._tunnel_host: + self.sock = sock + self._tunnel() + self.sock = ssl.wrap_socket(sock, + ca_certs=global_beinc_cert_file, + cert_reqs=ssl.CERT_REQUIRED) + + + +class ValidHTTPSHandler(urllib2.HTTPSHandler): + """ + Implements a simple CERT verification functionality + """ + + def https_open(self, req): + return self.do_open(ValidHTTPSConnection, req) + + + +def action_push(args): + """ + """ + try: + post_values = {'title': args.title, + 'message': args.message, + 'password': args.password} + data = urllib.urlencode(post_values) + req = urllib2.Request(args.url, data) + if args.cert: # check for cert validity + global global_beinc_cert_file # ugly hack + global_beinc_cert_file = args.cert + opener = urllib2.build_opener(ValidHTTPSHandler) + response = opener.open(req) + else: # ... or don't + response = urllib2.urlopen(req) + res_code = response.code + if res_code == 200: + print('Server responded: OK') + else: + print('Server responded: {0}'.format(res_code)) + print('Body:\n{0}'.format(response.read())) + response.close() + except urllib2.HTTPError as e: + sys.stderr.write('BEINC-server error ({0} - {1})\n'.format(e.code, e.reason)) + except Exception as e: + sys.stderr.write('BEINC generic client error: {0}\n'.format(e)) + sys.exit(errno.EPERM) + + +def main(): + + parser = argparse.ArgumentParser( + description='The following options are available') + + parser.add_argument('url', + metavar='URL', + type=str, + #dest='url', + #required=True, + help='Destination URL') + + parser.add_argument('-c', '--cert-file', + metavar='FILE', + type=str, + dest='cert', + default='', + help='BEINC CA-cert to check the server-cert against') + + parser.add_argument('-m', '--message', + metavar='MESSAGE', + type=str, + dest='message', + default='BEINC message', + help='BEINC message') + + parser.add_argument('-p', '--password', + metavar='PASSWORD', + type=str, + dest='password', + default='', + help='Password') + + parser.add_argument('-t', '--title', + metavar='TITLE', + type=str, + dest='title', + default='BEINC title', + help='BEINC title') + + parser.add_argument('-v', '--version', + action='version', + version='%(prog)s {0}'.format(__version__), + help='display program-version and exit') + + args = parser.parse_args() + + if not args.password: + try: + args.password = getpass.getpass() + except Exception as e: + sys.stderr.write('Prompt terminated\n') + sys.exit(errno.EACCES) + + action_push(args) + sys.exit(0) + + +if __name__ == '__main__': + main() diff --git a/beinc_server.json b/beinc_server.json index 2824dea..46674ed 100644 --- a/beinc_server.json +++ b/beinc_server.json @@ -18,27 +18,30 @@ }, "irc_client": { + "use_current_buffer": 0, "targets": [ { "name": "weechat_main", - "target_url": "", + "target_url": "https://10.0.0.2:9898/push/secondtest", "target_password": "changeme", "target_cert_file": "", "target_timestamp_format": "%H:%M:%S", - "pm_title_template": "", - "pm_message_template": "", - "cm_title_template": "", - "cm_message_template": "", - "nm_title_template": "", - "nm_message_template": "", + "pm_title_template": "%s @ %S", + "pm_message_template": "%m", + "cm_title_template": "%c @ %S", + "cm_message_template": "%s -> %m", + "nm_title_template": "%c @ %S", + "nm_message_template": "%s -> %m", "channel_list": ["RedpillLinpro.#python", - "Exile.#hin", + "Exile.#test", "RedpillLinpro.#adult", "Exile.#pichove"], "nick_list": ["Exile.Blackmore"], - "channel_messages_policy": 0, - "private_messages_policy": 0, - "notifications_policy": 0 + "channel_messages_policy": 2, + "private_messages_policy": 1, + "notifications_policy": 1, + "debug": 1, + "enabled": 1 } ] }, diff --git a/beinc_server.py b/beinc_server.py index 8687da3..d4dd3c3 100755 --- a/beinc_server.py +++ b/beinc_server.py @@ -1,18 +1,42 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# Blackmore's Enhanced IRC-Notification Collection (BEINC) v1.0 +# Copyright (C) 2013-2014 Simeon Simeonov + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + import argparse +import errno import getpass import json import os +import random import sys import cherrypy +try: + import pynotify +except ImportError as e: + pynotify = None + __author__ = 'Simeon Simeonov' -__version__ = '1.0-beta' -__license__ = "GPL3" +__version__ = '1.0' +__license__ = 'GPL3' BEINC_OSD_TYPE_NONE = 0 @@ -33,40 +57,35 @@ class BEINCInstance(object): self.__osd_type = BEINC_OSD_TYPE_NONE self.__osd_notification = None - try: - self.__name = instance_dict['name'] - self.__password = instance_dict['password'] - self.__queue_size = int(instance_dict['queue_size']) - - except Exception as e: - sys.stderr.write( - 'Instance processing error {0}:\n{1}\n'.format(self.__name, - e)) - sys.exit(1) + self.__name = instance_dict.get('name') + self.__password = instance_dict.get('password', '') + self.__queue_size = int(instance_dict.get('queue_size', 3)) if instance_dict['osd_system'].lower() == 'pynotify': + self.__queue_size = 0 # disable queueing if not pynotify: sys.stderr.write( 'This server does not possess pynotify capability\n') sys.stderr.write( 'Remove the instance {0}'.format(self.__name)) sys.stderr.write("or define it with 'osd_system': 'none'\n") - sys.exit(1) + sys.exit(errno.EPERM) try: self.__osd_notification = pynotify.Notification(' ') self.__osd_notification.set_timeout( - instance_dict['osd_timeout']) + int(instance_dict.get('osd_timeout', 5000))) self.__osd_notification.set_property( 'app_name', '{0} {1}'.format(sys.argv[0], __version__)) except Exception as e: sys.stderr.write( 'Unable to set up a notification object for {0} ({1})\n') - sys.exit(1) + sys.exit(errno.EPERM) self.__osd_type = BEINC_OSD_TYPE_PYNOTIFY + @property def name(self): """ @@ -129,34 +148,25 @@ def beinc_instance_login(method): """ decorator for checking login credentials """ - from functools import wraps - @wraps(method) - def tmp_func(self, *args, **kwargs): + def wrapper(self, *args, **kwargs): if not args: - raise cherrypy.HTTPError(400) - - print('args: {0}'.format(args)) - print('kwargs: {0}'.format(kwargs)) - print(cherrypy.request.config) - print('args[0]: {0} ({1})'.format(args[0], str(type(args[0])))) - print('instances: {0}'.format(str(self.__instances))) + raise cherrypy.HTTPError(status = 404) try: - instance = self.__instances[args[0]] + instance = self.instances[args[0]] except Exception as e: - sys.stderr.write('Wrong instance or password: {0}\n'.format(e)) - raise cherrypy.HTTPError('403 Forbidden', - 'Wrong instance or password') + raise cherrypy.HTTPError(status = 401, + message = 'Wrong instance or password') if not instance.password_match(kwargs.get('password')): - raise cherrypy.HTTPError('403 Forbidden', - 'Wrong instance or password') + raise cherrypy.HTTPError(status = 401, + message = 'Wrong instance or password') return method(self, *args, **kwargs) - return tmp_func + return wrapper class WebNotifyServer(object): @@ -167,15 +177,32 @@ class WebNotifyServer(object): self.__config = config self.__instances = dict() + # initialize pynotify if the module exists and if needed + if pynotify: + for instance in self.__config['server']['instances']: + # check if we have at least one instance that uses pynotify + # before initializing it + if instance.get('osd_system', '').lower() == 'pynotify': + if not pynotify.init('BEINC Notify'): + sys.stderr.write('pynotify.init failed! Exiting...\n') + sys.exit(1) + break try: for instance in self.__config['server']['instances']: self.__instances[instance['name']] = BEINCInstance(instance) print('Instance "{0}" added'.format(instance['name'])) except Exception as e: - sys.stderr.write('Unable to initialize queues: {0}\n'.format(e)) + sys.stderr.write('Unable to create instance "{0}": {1}\n'.format( + instance['name'], + e)) sys.exit(1) + + @property + def instances(self): + return self.__instances + @cherrypy.expose def index(self): """ @@ -190,33 +217,14 @@ class WebNotifyServer(object): """ return 'default' + @cherrypy.expose + @beinc_instance_login def push(self, *args, **kwargs): - print('push called') - - if not args: - raise cherrypy.HTTPError(400) - - # print('args: {0}'.format(args)) - # print('kwargs: {0}'.format(unicode(kwargs))) - # print(cherrypy.request.config) - # print('args[0]: {0} ({1})'.format(args[0], str(type(args[0])))) - # print('instances: {0}'.format(str(self.__instances))) - - try: - instance = self.__instances[args[0]] - except Exception as e: - sys.stderr.write('Wrong instance or password\n') - #print('DEBUG: {0}'.format(e)) - raise cherrypy.HTTPError('403 Forbidden', - 'Wrong instance or password') - if not instance.password_match(kwargs.get('password')): - sys.stderr.write('Wrong instance or password\n') - raise cherrypy.HTTPError('403 Forbidden', - 'Wrong instance or password') + instance = self.__instances[args[0]] -# instance = self.__instances[args[0]] + print('**kwargs: {0}'.format(str(kwargs))) title = kwargs.get('title', '') message = kwargs.get('message', '') try: @@ -229,12 +237,19 @@ class WebNotifyServer(object): e)) raise cherrypy.HTTPError(500, 'Unable to send message') + @cherrypy.expose @beinc_instance_login def pull(self, *args, **kwargs): - instance = self.__instances(args[0]) - return 'OK' + instance = self.__instances[args[0]] + if not instance.queueable: + raise cherrypy.HTTPError( + status = 405, + message = 'BEINC instance "{0}" does not support queuing'.format( + instance.name)) + + return instance.get_queue() def main(): @@ -283,7 +298,7 @@ def main(): except Exception as e: sys.stderr.write('Unable to parse {0}: {1}'.format(args.config_file, e)) - sys.exit(1) + sys.exit(errno.EIO) cherrypy.config.update({ 'server.socket_host': args.hostname, @@ -292,20 +307,11 @@ def main(): 'server.ssl_certificate': config_dict['server']['general']['ssl_certificate'], 'server.ssl_private_key': config_dict['server']['general']['ssl_private_key'], 'tools.encode.on': True, - 'tools.encode.encoding': 'utf-8' + 'tools.encode.encoding': 'utf-8', + 'tools.log_tracebacks.on': False, + 'request.show_tracebacks': False }) - global pynotify - try: - import pynotify - if not pynotify.init('BEINC Notify'): - sys.stderr.write('pynotify.init failed! Exiting...\n') - sys.exit(1) - except Exception as e: - sys.stderr.write( - 'Notice: pynotify support unavailable ({0})\n'.format(e)) - pynotify = False - try: cherrypy.quickstart(WebNotifyServer(config_dict)) diff --git a/beinc_weechat.py b/beinc_weechat.py index 689f450..8b4392f 100644 --- a/beinc_weechat.py +++ b/beinc_weechat.py @@ -1,6 +1,23 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +# Blackmore's Enhanced IRC-Notification Collection (BEINC) v1.0 +# Copyright (C) 2013-2014 Simeon Simeonov + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + + import datetime import httplib import json @@ -14,6 +31,12 @@ import urllib2 import weechat + +__author__ = 'Simeon Simeonov' +__version__ = '1.0' +__license__ = 'GPL3' + + enabled = True global_values = dict() @@ -26,14 +49,13 @@ BEINC_POLICY_LIST_ONLY = 2 class ValidHTTPSConnection(httplib.HTTPConnection): """ + Implements a simple CERT verification functionality """ default_port = httplib.HTTPS_PORT - def __init__(self, cert_file, *args, **kwargs): + def __init__(self, *args, **kwargs): httplib.HTTPConnection.__init__(self, *args, **kwargs) - self.__cert_file = cert_file - def connect(self): sock = socket.create_connection((self.host, self.port), @@ -42,19 +64,18 @@ class ValidHTTPSConnection(httplib.HTTPConnection): self.sock = sock self._tunnel() self.sock = ssl.wrap_socket(sock, - ca_certs=self.__cert_file, + ca_certs=global_beinc_cert_file, cert_reqs=ssl.CERT_REQUIRED) class ValidHTTPSHandler(urllib2.HTTPSHandler): - - def __init__(self, cert_file, *args, **kwargs): - urllib2.HTTPSHandler.__init__(self, *args, **kwargs) - self.__cert_file = cert_file + """ + Implements a simple CERT verification functionality + """ def https_open(self, req): - return self.do_open(ValidHTTPSConnection(self.__cert_file), req) + return self.do_open(ValidHTTPSConnection, req) @@ -101,6 +122,8 @@ class WeechatTarget(object): self.__cert_file = target_dict.get('target_cert_file') self.__timestamp_format = target_dict.get('target_timestamp_format', '%H:%M:%S') + self.__debug = bool(target_dict.get('debug', False)) + self.__enabled = bool(target_dict.get('enabled', True)) @property @@ -144,48 +167,117 @@ class WeechatTarget(object): """ return self.__notifications_policy - + + @property + def enabled(self): + """ + """ + return self.__enabled + + @enabled.setter + def enabled(self, value): + """ + """ + self.__enabled = value + + def __repr__(self): """ """ - - return 'name: {0}\nurl: {1}\nchannel_list: {2}\nnick_list: {3}'\ - 'channel_messages_policy: {4}\nprivate_messages_policy: {5}'\ - 'notifications_policy: {6}'.format(self.__name, - self.__url, - ', '.join(self.__chans), - ', '.join(self.__nicks), - self.__chan_message_policy, - self.__priv_message_policy, - self.__notifications_policy) - - - def send_private_message_notification(self, message, values): + return 'name: {0}\nurl: {1}\nchannel_list: {2}\nnick_list: {3}\n'\ + 'channel_messages_policy: {4}\nprivate_messages_policy: {5}\n'\ + 'notifications_policy: {6}\nenabled: {7}\n\n'.format( + self.__name, + self.__url, + ', '.join(self.__chans), + ', '.join(self.__nicks), + self.__chan_messages_policy, + self.__priv_messages_policy, + self.__notifications_policy, + 'yes' if self.__enabled else 'no') + + + def send_private_message_notification(self, values): """ """ - pass + try: + title_str = self.__fetch_formatted_str(self.__pm_title_template, + values) + message_str = self.__fetch_formatted_str(self.__pm_message_template, + values) + post_values = {'title': title_str, + 'message': message_str, + 'password': self.__password} + data = urllib.urlencode(post_values) + if self.__send_beinc_message(data) and self.__debug: + beinc_prnt( + 'BEINC DEBUG: send_private_message_notification-ERROR ' + 'for "{0}": __send_beinc_message -> False'.format( + self.__name)) + except Exception as e: + if self.__debug: + beinc_prnt( + 'BEINC DEBUG: send_private_message_notification-ERROR ' + 'for "{0}": {1}'.format(self.__name, e)) - def send_channel_message_notification(self, message, values): + def send_channel_message_notification(self, values): """ """ - pass + try: + title_str = self.__fetch_formatted_str(self.__cm_title_template, + values) + message_str = self.__fetch_formatted_str(self.__cm_message_template, + values) + post_values = {'title': title_str, + 'message': message_str, + 'password': self.__password} + data = urllib.urlencode(post_values) + if self.__send_beinc_message(data) and self.__debug: + beinc_prnt( + 'BEINC DEBUG: send_channel_message_notification-ERROR ' + 'for "{0}": __send_beinc_message -> False'.format( + self.__name)) + except Exception as e: + if self.__debug: + beinc_prnt( + 'BEINC DEBUG: send_channel_message_notification-ERROR ' + 'for "{0}": {1}'.format(self.__name, e)) - - def send_notify_message_notification(self, message, values): + + def send_notify_message_notification(self, values): """ """ - pass + try: + title_str = self.__fetch_formatted_str(self.__nm_title_template, + values) + message_str = self.__fetch_formatted_str(self.__nm_message_template, + values) + post_values = {'title': title_str, + 'message': message_str, + 'password': self.__password} + data = urllib.urlencode(post_values) + if self.__send_beinc_message(data) and self.__debug: + beinc_prnt( + 'BEINC DEBUG: send_notify_message_notification-ERROR ' + 'for "{0}": __send_beinc_message -> False'.format( + self.__name)) + except Exception as e: + if self.__debug: + beinc_prnt( + 'BEINC DEBUG: send_notify_message_notification-ERROR ' + 'for "{0}": {1}'.format(self.__name, e)) def __fetch_formatted_str(self, template, values): """ """ + timestamp = datetime.datetime.now().strftime(self.__timestamp_format) replacements = {'%S': values['server'], '%s': values['source_nick'], '%c': values['channel'], '%m': values['message'], - '%t': values['timestamp'], + '%t': timestamp, '%p': 'BEINC', '%n': values['own_nick']} for key, value in replacements.items(): @@ -201,40 +293,100 @@ class WeechatTarget(object): try: req = urllib2.Request(self.__url, data) - opener = urllib2.build_opener(ValidHTTPSHandler) - - response = opener.open(req) + + if self.__cert_file: + opener = urllib2.build_opener(ValidHTTPSHandler) + response = opener.open(req) + else: + response = urllib2.urlopen(req) res_code = response.code response.close() if res_code == 200: return True - except Exception as e: - weechat.prnt(weechat.current_buffer(), - 'DEBUG: send_beinc_message-ERROR: {0}'.format(e)) + except urllib2.HTTPError as e: + if self.__debug: + beinc_prnt( + 'BEINC DEBUG: send_beinc_message-ERROR for "{0}": {1} ->' + ' ({2} - {3})'.format(self.__name, e.url, e.code, e.reason)) + # all other exception should be handled by the caller return False -def beinc_send_message(message): - weechat.prnt(weechat.current_buffer(), 'beinc message: {0}'.format(message)) +def beinc_prnt(message_str): + """ + wrapper around weechat.prnt + """ + if global_values['use_current_buffer']: + weechat.prnt(weechat.current_buffer(), message_str) + else: + weechat.prnt('', message_str) + +def beinc_cmd_target_handler(cmd_tokens): + """ + handles: '/beinc target' command actions + """ + if not cmd_tokens or cmd_tokens[0] not in ['list', 'enable', 'disable']: + beinc_prnt('beinc target [ list | enable | disable ]') + return weechat.WEECHAT_RC_OK -def beinc_command(data, buffer, args): + if cmd_tokens[0] == 'list': + beinc_prnt('--- Targets ---') + for target in target_list: + beinc_prnt(str(target)) + beinc_prnt('---------------') + elif cmd_tokens[0] == 'enable': + if not cmd_tokens[1:]: + beinc_prnt('missing a name-argument') + return weechat.WEECHAT_RC_OK + name = ' '.join(cmd_tokens[1:]) + for target in target_list: + if target.name == name: + target.enabled = True + beinc_prnt('target "{0}" enabled'.format(name)) + break + else: + beinc_prnt('no matching target for "{0}"'.format(name)) + elif cmd_tokens[0] == 'disable': + if not cmd_tokens[1:]: + beinc_prnt('missing a name-argument') + return weechat.WEECHAT_RC_OK + name = ' '.join(cmd_tokens[1:]) + for target in target_list: + if target.name == name: + target.enabled = False + beinc_prnt('target "{0}" disabled'.format(name)) + break + else: + beinc_prnt('no matching target for "{0}"'.format(name)) + + return weechat.WEECHAT_RC_OK + + +def beinc_command(data, buffer_obj, args): global enabled + cmd_tokens = args.split() + + if not cmd_tokens: + return weechat.WEECHAT_RC_OK + if args == 'on': enabled = True - weechat.prnt(weechat.current_buffer(), 'beinc on') + beinc_prnt('BEINC on') elif args == 'off': enabled = False - weechat.prnt(weechat.current_buffer(), 'beinc off') + beinc_prnt('BEINC off') elif args == 'reload': - beinc_config_file_str = os.path.join( - weechat.info_get('weechat_dir', ''), - 'beinc.json') - weechat.prnt(weechat.current_buffer(), '{0} reloaded'.format( - beinc_config_file_str)) + beinc_prnt('Reloading BEINC...') + beinc_init() + elif cmd_tokens[0] == 'target': + return beinc_cmd_target_handler(cmd_tokens[1:]) else: - beinc_send_message(args) + beinc_prnt('data: {0}, cmd_tokens: {1}, args: {2}'.format( + str(data), + str(cmd_tokens), + str(args))) return weechat.WEECHAT_RC_OK @@ -249,40 +401,74 @@ def beinc_privmsg_handler(data, signal, signal_data): # packing the privmsg handler values ph_values = dict() ph_values['server'] = signal.split(',')[0] - ph_values['own_nick'] = weechat.info_get('irc_nick', server) + ph_values['own_nick'] = weechat.info_get('irc_nick', ph_values['server']) ph_values['channel'] = prvmsg_dict['arguments'].split(':')[0].strip() ph_values['source_nick'] = prvmsg_dict['nick'] ph_values['message'] = ':'.join( prvmsg_dict['arguments'].split(':')[1:]).strip() - ph_values['timestamp'] = datetime.datetime.now().strftime( - self.__timestamp_format) if ph_values['channel'] == ph_values['own_nick']: # priv messages are handled here - if not global_values['global_channel_messages_policy']: + if not global_values['global_private_messages_policy']: + return weechat.WEECHAT_RC_OK + + if global_values['global_private_messages_policy'] == BEINC_POLICY_LIST_ONLY \ + and '{0}.{1}'.format( + ph_values['server'], + ph_values['source_nick'].lower()) not in global_values['global_nicks']: return weechat.WEECHAT_RC_OK for target in target_list: - if target.private_messages_policy == 1 or ( - target.private_messages_policy == 2 \ + if not target.enabled: + continue + if target.private_messages_policy == BEINC_POLICY_ALL or ( + target.private_messages_policy == BEINC_POLICY_LIST_ONLY \ and '{0}.{1}'.format( ph_values['server'], ph_values['source_nick'].lower()) in target.nicks): - weechat.prnt(weechat.current_buffer(), - 'DEBUG: priv message - {0}'.format( - ph_values['message'])) + target.send_private_message_notification(ph_values) - elif privmsg_handler_values['own_nick'].lower() in ph_values['message'].lower(): + elif ph_values['own_nick'].lower() in ph_values['message'].lower(): # notify messages are handled here - weechat.prnt(weechat.current_buffer(), - 'DEBUG: notify message - {0}'.format(ph_values['message'])) if not global_values['global_notifications_policy']: return weechat.WEECHAT_RC_OK + if global_values['global_notifications_policy'] == BEINC_POLICY_LIST_ONLY \ + and '{0}.{1}'.format( + ph_values['server'], + ph_values['channel'].lower()) not in global_values['global_chans']: + return weechat.WEECHAT_RC_OK + + for target in target_list: + if not target.enabled: + continue + if target.notifications_policy == BEINC_POLICY_ALL or ( + target.notifications_policy == BEINC_POLICY_LIST_ONLY \ + and '{0}.{1}'.format( + ph_values['server'], + ph_values['channel'].lower()) in target.chans): + target.send_notify_message_notification(ph_values) + elif global_values['global_channel_messages_policy']: # chan messages are handled here - weechat.prnt(weechat.current_buffer(), - 'DEBUG: chan message - {0}'.format(ph_values['message'])) + if not global_values['global_notifications_policy']: + return weechat.WEECHAT_RC_OK + + if global_values['global_channel_messages_policy'] == BEINC_POLICY_LIST_ONLY \ + and '{0}.{1}'.format( + ph_values['server'], + ph_values['channel'].lower()) not in global_values['global_chans']: + return weechat.WEECHAT_RC_OK + + for target in target_list: + if not target.enabled: + continue + if target.channel_messages_policy == BEINC_POLICY_ALL or ( + target.channel_messages_policy == BEINC_POLICY_LIST_ONLY \ + and '{0}.{1}'.format( + ph_values['server'], + ph_values['channel'].lower()) in target.chans): + target.send_channel_message_notification(ph_values) return weechat.WEECHAT_RC_OK @@ -293,33 +479,36 @@ def beinc_init(): global target_list global global_values + # global chans/nicks sets are used to speed up the filtering + global_values = dict() global_values['global_chans'] = set() global_values['global_nicks'] = set() - custom_error = '' + target_list = list() + custom_error = '' global_values['global_channel_messages_policy'] = False global_values['global_private_messages_policy'] = False global_values['global_notifications_policy'] = False - + global_values['use_current_buffer'] = False + try: beinc_config_file_str = os.path.join( weechat.info_get('weechat_dir', ''), 'beinc.json') - weechat.prnt('', 'Parsing {0}...'.format(beinc_config_file_str)) + beinc_prnt('Parsing {0}...'.format(beinc_config_file_str)) custom_error = 'load error' with open(beinc_config_file_str, 'r') as fp: config_dict = json.load(fp) - # clear the target-list - target_list = [] - custom_error = 'target parse error' + global_values['use_current_buffer'] = bool(config_dict['irc_client'].get( + 'use_current_buffer', False)) for target in config_dict['irc_client']['targets']: try: new_target = WeechatTarget(target) except Exception as e: - weechat.prnt('', 'Unable to add target: {0}'.format(e)) + beinc_prnt('Unable to add target: {0}'.format(e)) continue global_values['global_chans'].update(new_target.chans) global_values['global_nicks'].update(new_target.nicks) @@ -331,12 +520,12 @@ def beinc_init(): global_values['global_notifications_policy'] = True target_list.append(new_target) - weechat.prnt('', 'BEINC target {0} added'.format(new_target.name)) + beinc_prnt('BEINC target "{0}" added'.format(new_target.name)) - weechat.prnt('', 'Done!!!') + beinc_prnt('Done!') except Exception as e: - weechat.prnt('', 'ERROR: unable to parse {0}: {1} - {2}'.format( + beinc_prnt('ERROR: unable to parse {0}: {1} - {2}'.format( beinc_config_file_str, custom_error, e)) enabled = False diff --git a/bosd.py b/bosd.py deleted file mode 100644 index d678754..0000000 --- a/bosd.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import urllib -import urllib2 - -import weechat - -#### CONFIG #### -enabled = True - -notify_channels = [ - "RedpillLinpro.#python", - "Exile.#hin", - "RedpillLinpro.#adult", - "Exile.#pichove" - ] - -connections = [ {'bosd_url': 'https://127.0.0.1:9999/npush/', - 'bosd_password': '1234'}, - -# {'bosd_url': 'https://pichove.org:9999/npush/', -# 'bosd_port': 9999, -# 'bosd_password': 'foo'}, - ] -################ - -__VERSION__ = '2.0' - -def bosd_send_message(header='', message=''): - for conn in connections: - try: - conn['nheader'] = header # notification header - conn['nmessage'] = message # notification message - - data = urllib.urlencode(conn) - - req = urllib2.Request(url, data) - urllib2.urlopen(req) - #weechat.prnt("", message) - except: - continue - - return True - - -def bosd_command(data, buffer, args): - global enabled - if args == 'on': - enabled = True - weechat.prnt(weechat.current_buffer(), "bosd on") - elif args == 'off': - enabled = False - weechat.prnt(weechat.current_buffer(), "bosd off") - else: - bosd_send_message('BOSD generic', args) - - return weechat.WEECHAT_RC_OK - - -def bosd_privmsg_handler(data, signal, signal_data): - if not enabled: - return weechat.WEECHAT_RC_OK - - prvmsg_dict = weechat.info_get_hashtable("irc_message_parse", - { "message": signal_data }) - - - server = signal.split(",")[0] - - # channel = signal_data.split(":")[-1] - # my_nick = weechat.info_get("irc_nick_from_host", signal_data) - - my_nick = weechat.info_get("irc_nick", server) - channel = prvmsg_dict['arguments'].split(":")[0].strip() - nick = prvmsg_dict['nick'] - message = ':'.join(prvmsg_dict['arguments'].split(':')[1:]).strip() - - if (my_nick in message) or ('{0}.{1}'.format(server,channel) in notify_channels): - template_msg = '{0} @ {1} - {2}: {3}'.format(channel, - server, - nick, - message) - bosd_send_xosd_message(template_msg) - - if my_nick in channel: - template_msg = '{0} @ {1}: {2}'.format(nick, server, message) - bosd_send_xosd_message(template_msg) - - #my_str = "%s - %s - %s - %s" % (my_nick, server, channel, message) - #weechat.prnt("", my_str) - - return weechat.WEECHAT_RC_OK - - - -weechat.register('bosd', 'Simeon Simeonov', '1.0', 'GPL3', 'Socket notification script', "", "") -weechat.hook_command("bosd", "bosd on off toggle", "", "description...", "None", "bosd_command", "") -weechat.hook_signal("*,irc_in2_privmsg", "bosd_privmsg_handler", "") - -weechat.prnt("", "bosd initiated!") diff --git a/bpynotify_orm.py b/bpynotify_orm.py deleted file mode 100644 index 0540d0a..0000000 --- a/bpynotify_orm.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- - -import datetime - -from sqlalchemy import schema, types -from sqlalchemy.orm import mapper - -metadata = schema.MetaData() - -notification_entry_table = schema.Table('notification_entries', metadata, - schema.Column('id', types.Integer, primary_key=True), - schema.Column('timestamp', types.DateTime), - schema.Column('message', types.Unicode(), default = u'Empty message'), - schema.Column('viewed', types.Boolean, default=False) - ) - - - -class NotificationEntry(object): - - def __init__(self, message): - - self.timestamp = datetime.datetime.now() - self.message = message - - - def __repr__(self): - - return message - - -mapper(NotificationEntry, notification_entry_table) diff --git a/socket_server.py b/socket_server.py deleted file mode 100755 index c68e500..0000000 --- a/socket_server.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import SocketServer -import os -import sys - -from sqlalchemy import create_engine -from sqlalchemy.orm import sessionmaker - -from bpynotify_orm import NotificationEntry, notification_entry_table - - -class CustomSocketServer(SocketServer.TCPServer): - - def __init__(self, server_address, RequestHandlerClass, session): - #super(CustomSocketServer, self).__init__(server_address, - # RequestHandlerClass) - SocketServer.TCPServer.__init__(self, - server_address, - RequestHandlerClass) - self.session = session - - -class MyTCPHandler(SocketServer.StreamRequestHandler): - """ - The RequestHandler class for our server. - - It is instantiated once per connection to the server, and must - override the handle() method to implement communication to the - client. - """ - - def handle(self): - - self.data = self.rfile.readline().decode('utf8').strip() - #print(self.data) - entry = NotificationEntry(self.data) - self.server.session.add(entry) - self.server.session.commit() - - -def main(): - - HOST, PORT = "localhost", 9997 - - if len(sys.argv) == 2 and sys.argv[1] == '-d': - try: - pid = os.fork() - if pid > 0: - sys.exit(0) - except Exception as e: - sys.stderr.write("Unable to daemonize. Fork error: {0}".format(e)) - sys.exit(1) - - try: - - engine = create_engine('sqlite:///notifications.db') - Session = sessionmaker(bind=engine) # bound session - session = Session() - - server = CustomSocketServer((HOST, PORT), MyTCPHandler, session) - - # clean all previous entries # - notification_entry_table.delete(bind=engine).execute() - - server.serve_forever() - - except Exception as e: - sys.stderr.write("Server error: {0}".format(e)) - sys.exit(1) - - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/web_server.py b/web_server.py deleted file mode 100755 index cec8c38..0000000 --- a/web_server.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import sys - -import cherrypy - -class WebNotifyServer(object): - - def __init__(self): - self.counter = 0 - - @cherrypy.expose - def notifications(self, **kwargs): - self.counter += 1 - print(str(kwargs)) - print(self.counter) - return ("called") - - - @cherrypy.expose - def other(self, **kwargs): - self.counter += 1 - print(str(kwargs)) - print(self.counter) - return ("called") - - -def main(): - - cherrypy.config.update({ - 'server.socket_host': '10.0.0.4', - 'server.socket_port': 40003, - }) - - try: - cherrypy.quickstart(WebNotifyServer()) - - except Exception as e: - sys.stderr.write("WebServer error: {0}".format(e)) - sys.exit(1) - - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/weechat_notify.py b/weechat_notify.py deleted file mode 100755 index 897f26d..0000000 --- a/weechat_notify.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import json -import urllib2 -import sched -import sys -import time - -import pynotify - -POLLING_FREQUENCY = 10 -NOTIFICATION_URL = 'https://simeon.simeonov.no:40004/notifications/' -TIMEOUT_SEC = 3 - - -def poll_notifications(scheduler): - """ - """ - try: - req = urllib2.Request(NOTIFICATION_URL) - response = urllib2.urlopen(req) - response_str = response.read() - - entries = json.loads(response_str) - for entry in entries: - n = pynotify.Notification('IRC', entry, 'dialog-information') - n.set_timeout(TIMEOUT_SEC) - n.show() - - except Exception as e: - sys.stderr.write("Client error: {0}".format(e)) - sys.exit(1) - - scheduler.enter(POLLING_FREQUENCY, 1, poll_notifications, (scheduler,)) - - -def main(): - - if not pynotify.init("Weechat Notify"): - sys.stderr.write("There was a problem with libnotify") - sys.exit(1) - - sc = sched.scheduler(time.time, time.sleep) - sc.enter(POLLING_FREQUENCY, 1, poll_notifications, (sc,)) - sc.run() - -if __name__ == '__main__': - main() diff --git a/weechat_notify_server.py b/weechat_notify_server.py deleted file mode 100755 index 35d4f42..0000000 --- a/weechat_notify_server.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -import json -import SocketServer -import os -import sys - -from multiprocessing import Process, Queue - -import cherrypy - -import settings - - -class CustomSocketServer(SocketServer.TCPServer): - - def __init__(self, server_address, RequestHandlerClass, queue): - SocketServer.TCPServer.__init__(self, - server_address, - RequestHandlerClass) - self.queue = queue - - -class MyTCPHandler(SocketServer.StreamRequestHandler): - """ - The RequestHandler class for our server. - - It is instantiated once per connection to the server, and must - override the handle() method to implement communication to the - client. - """ - - def handle(self): - - data = self.rfile.readline().strip() - - if self.server.queue.qsize() > 3: - self.server.queue.get() - - self.server.queue.put(data) - #print(self.data) - - -class WebNotifyServer(object): - - def __init__(self, queue): - self.queue = queue - - @cherrypy.expose - def notifications(self): - - entry_list = list() - - while not self.queue.empty(): - entry_list.append(self.queue.get(False)) - - #print (json.dumps(entry_list, sort_keys=True, indent=4)) - return json.dumps(entry_list) - - -def socket_server(queue): - - try: - server = CustomSocketServer((settings.SOCKET_SERVER_HOST, - settings.SOCKET_SERVER_PORT), - MyTCPHandler, - queue) - server.serve_forever() - - except Exception as e: - sys.stderr.write("SocketServer error: {0}".format(e)) - sys.exit(1) - - sys.exit(0) - - - -def web_server(queue): - - cherrypy.config.update({ - 'server.socket_host': settings.WEB_SERVER_HOST, - 'server.socket_port': settings.WEB_SERVER_PORT, - 'server.ssl_module': 'pyopenssl', - 'server.ssl_certificate': settings.WEB_SERVER_CERT, - 'server.ssl_private_key': settings.WEB_SERVER_KEY, - }) - - try: - - cherrypy.quickstart(WebNotifyServer(queue)) - - except Exception as e: - sys.stderr.write("WebServer error: {0}".format(e)) - sys.exit(1) - - sys.exit(0) - - -def main(): - - q = Queue() - - socket_server_process = Process(target=socket_server, args=(q,)) - web_server_process = Process(target=web_server, args=(q,)) - - web_server_process.start() - socket_server_process.start() - - socket_server_process.join() - web_server_process.join() - - sys.exit(0) - -if __name__ == "__main__": - main() -- cgit v1.3