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_weechat.py | 331 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 260 insertions(+), 71 deletions(-) (limited to 'beinc_weechat.py') 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 -- cgit v1.3