diff --git a/.gitignore b/.gitignore index 7617a01..f37fd5c 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,11 @@ *.log config.ini log/ + +\.project + +\.pydevproject + +\.settings/ + +\.idea/ diff --git a/.travis.yml b/.travis.yml index d1103be..0082739 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ sudo: required branches: only: - master - - beta - develop before_script: diff --git a/CHANGELOG.md b/CHANGELOG.md index d317f04..62f0368 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,17 +1,53 @@ # Changelog -### __[v2.3]__ - unreleased + +### __[v2.#]__ - Unreleased +##### Added +##### Changed +##### Deprecated +##### Removed +- Notify-my-Andoird Plugin und Logging-Handler wegen Einstellung des Service entfernt [#374](https://github.com/Schrolli91/BOSWatch/pull/374) +##### Fixed +##### Security + + +### __[v2.4]__ - 17.08.2018 +##### Added +- Config Eintrag um Port für MySQL Plugin festzulegen [#345](https://github.com/Schrolli91/BOSWatch/pull/345) +- FMS und ZVEI Support für Pushover Plugin [#352](https://github.com/Schrolli91/BOSWatch/pull/352) +- Benutzerdefinierte Nachrichten für Pushover Plugin in config [#352](https://github.com/Schrolli91/BOSWatch/pull/352) +##### Changed +- multicastAlarm Plugin - RICs die von multicastAlarm genutzt werden, müssen nicht mehr in der config bei allow_ric bzw. filter_range_start/filter_range_end berücksichtigt werden. [#357](https://github.com/Schrolli91/BOSWatch/pull/357) +- FFAgent Plugin - Debug Logging für die alarmHeaders eingebaut zwecks Troubleshooting [#354](https://github.com/Schrolli91/BOSWatch/pull/354) +- multicastAlarm Plugin - Buffer nach jedem Alarm löschen - erlaubt in kombination mit "doubleFilter_check_msg" die Verwendung in Netzen, die zwischen multicastAlarm RICs auch normale Alarme senden. [#370](https://github.com/Schrolli91/BOSWatch/pull/370) +##### Fixed +- Fehler beim Auslesen der netIdent_RIC im MySQL Plugin [#347](https://github.com/Schrolli91/BOSWatch/pull/347) +- FFAgent Plugin - Typo bei alarmHeaders für Live Betrieb gefixt [#354](https://github.com/Schrolli91/BOSWatch/pull/354) + + +### __[v2.3]__ - 22.12.2017 +##### Added +- zuschaltbare POCSAG Multicast-Alarm Funktionalität [#307](https://github.com/Schrolli91/BOSWatch/pull/307) +- Flag in Config um nur letzte Net Ident oder gesamte Historie zu speichern [#317](https://github.com/Schrolli91/BOSWatch/pull/317) +##### Removed +- Beta Branch aus Readme, Installer und Travis-CI entfernt [#324](https://github.com/Schrolli91/BOSWatch/pull/324) +##### Fixed +- Bug in httpRequest Plugin (data Field wurde überschrieben) [#337](https://github.com/Schrolli91/BOSWatch/pull/337) +- Kommentar für FirEmergency Einstellung angepasst [#338](https://github.com/Schrolli91/BOSWatch/pull/338) + + +### __[v2.2.2]__ - 21.10.2017 ##### Added - Installations Script für Services [#316](https://github.com/Schrolli91/BOSWatch/pull/316) ##### Changed - Telegram Plugin importiert Google Maps Funktionen nur noch wenn API Key eingetragen ist [#315](https://github.com/Schrolli91/BOSWatch/pull/315) - Versions Nummer und Branch Name getrennt [3fed1ac](https://github.com/Schrolli91/BOSWatch/commit/3fed1ac12af8690213766e0e81d71c237530ed2c) ##### Deprecated -##### Removed +- Beta Branch wird mit nächstem Update entfernt [Forum](http://boswatch.de/index.php?thread/16-beta-branch-abschaffen/&postID=113#post113) ##### Fixed +- Schreibfehler der Pfadangabe im Installer [#317](https://github.com/Schrolli91/BOSWatch/pull/317) - Schreibfehler in Service Readme [#313](https://github.com/Schrolli91/BOSWatch/issues/313) - Einige Code-Style Verbesserungen [#310](https://github.com/Schrolli91/BOSWatch/pull/310) -##### Security ### __[v2.2.1]__ - 19.09.2017 @@ -36,7 +72,7 @@ Zum schreiben des Changelog's siehe: http://keepachangelog.com/de/1.0.0/ -### __[version]__ - date +### __[v#.#]__ - date ##### Added ##### Changed ##### Deprecated diff --git a/Konzept.md b/Konzept.md index 6e3a5b1..7903dcc 100644 --- a/Konzept.md +++ b/Konzept.md @@ -2,6 +2,7 @@ ============ +Python 3 Verpacken der Funktionalitäten in Klassen um OOP-Grundsätze zu erreichen. @@ -12,11 +13,13 @@ Verpacken der Funktionalitäten in Klassen um OOP-Grundsätze zu erreichen. - reine Dekodierung mittels rtl-fm und multimon - Keine Filter usw. nur die Dekoder, Daten verpacken, verschicken - per TCP Socket an den Server + - versch Eingabequellen (DVB-T Stick, Audio Eingang) ### Server: - Empfängt die TCP Socket Pakete der einzelnen Clients - Durch doubleFiltering fallen doppelt eingehende Alarme der Clienten sowieso raus - - Danach Filterung usw. dann call an die plugins + - Danach Filterung nach neuen Filterkonzept + - dann call an die plugins diff --git a/README.md b/README.md index eb8e805..c9b570b 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,11 @@ +### Arbeiten an BOSWatch 3 gestartet +#### Work on BOSWatch 3 has started +## see: https://boswatch.de/index.php?thread/29-boswatch-3/ + + |Branch|Code Qualität|CI-Build| |---|---|---| |master|[![Codacy Badge](https://img.shields.io/codacy/grade/d512976554354a199555bd34ed179bb1/master.svg)](https://www.codacy.com/app/Schrolli91/BOSWatch/dashboard?bid=3763821)|[![Build Status](https://travis-ci.org/Schrolli91/BOSWatch.svg?branch=master)](https://travis-ci.org/Schrolli91/BOSWatch)| -|beta|[![Codacy Badge](https://img.shields.io/codacy/grade/d512976554354a199555bd34ed179bb1/beta.svg)](https://www.codacy.com/app/Schrolli91/BOSWatch/dashboard?bid=4213030)|[![Build Status](https://travis-ci.org/Schrolli91/BOSWatch.svg?branch=beta)](https://travis-ci.org/Schrolli91/BOSWatch)| |develop|[![Codacy Badge](https://img.shields.io/codacy/grade/d512976554354a199555bd34ed179bb1/develop.svg)](https://www.codacy.com/app/Schrolli91/BOSWatch/dashboard?bid=3763820)|[![Build Status](https://travis-ci.org/Schrolli91/BOSWatch.svg?branch=develop)](https://travis-ci.org/Schrolli91/BOSWatch)| @@ -47,6 +51,7 @@ unless you are developer you can use the develop-Branch - may be unstable! - Ready for use BOSWatch as daemon - possibility to start plugins asynchron - NMA Error Handler +- multicastAlarm for transmission optimized networks ### Plugins diff --git a/boswatch.py b/boswatch.py index 6cdbeeb..7c250fa 100755 --- a/boswatch.py +++ b/boswatch.py @@ -268,6 +268,8 @@ try: # if given loglevel is debug: if globalVars.config.getint("BOSWatch","loglevel") == 10: configHandler.checkConfig("BOSWatch") + configHandler.checkConfig("multicastAlarm") + configHandler.checkConfig("Filters") configHandler.checkConfig("FMS") configHandler.checkConfig("ZVEI") configHandler.checkConfig("POC") @@ -291,29 +293,6 @@ try: logging.error("cannot set loglevel of fileHandler") logging.debug("cannot set loglevel of fileHandler", exc_info=True) - # - # Add NMA logging handler - # - try: - if configHandler.checkConfig("NMAHandler"): - # is NMAHandler enabled? - if globalVars.config.getboolean("NMAHandler", "enableHandler") == True: - # we only could do something, if an APIKey is given: - if len(globalVars.config.get("NMAHandler","APIKey")) > 0: - logging.debug("add NMA logging handler") - from includes import NMAHandler - if globalVars.config.get("NMAHandler","appName") == "": - nmaHandler = NMAHandler.NMAHandler(globalVars.config.get("NMAHandler","APIKey")) - else: - nmaHandler = NMAHandler.NMAHandler(globalVars.config.get("NMAHandler","APIKey"), globalVars.config.get("NMAHandler","appName")) - nmaHandler.setLevel(globalVars.config.getint("NMAHandler","loglevel")) - myLogger.addHandler(nmaHandler) - except: - # It's an error, but we could work without that stuff... - logging.error("cannot add NMA logging handler") - logging.debug("cannot add NMA logging handler", exc_info=True) - - # initialization was fine, continue with main program... # diff --git a/citest/config.httpRequest.ini b/citest/config.httpRequest.ini index bfa08ec..512070a 100644 --- a/citest/config.httpRequest.ini +++ b/citest/config.httpRequest.ini @@ -114,6 +114,26 @@ ricd = Unwetter # Usually sent periodically, separated by comma netIdent_ric = 0174760, 1398098 + +[multicastAlarm] +# Configure multicastAlarm if your POCSAG network uses an optimized transmission scheme for alarms with more than one RIC (often found in Swissphone networks). +# In this optimized transmission scheme, a POCSAG telegram with each RIC that needs to be alarmed will be send in a sequence. These telegrams are send without a text message. This sequence is directly followed by a telegram with a specific RIC and the text message that belongs to the sequnece send right before. +# A POCSAG pager (DME) can be configured to start an acoustic alarm if a specific RIC without text has been received. If afterwards the specific RIC with the text message will be received, the pager will show the message in it's display. +# multicastAlarm enables BOSwatch to process the all received RICs joined with the text message. +# +# enable multicastAlarm (0 - off | 1 - on) +multicastAlarm = 0 + +# time limit for alarms that do not belong to the multicastAlarm sequence in seconds +multicastAlarm_ignore_time = 15 + +# multicastAlarm delimiter RIC (usually used as a starting point for a alarm sequence) (can be empty) +multicastAlarm_delimiter_ric = + +# multicastAlarm RIC that is used to send the text message +multicastAlarm_ric = + + [Filters] # RegEX Filter Configuration # http://www.regexr.com/ - RegEX Test Tool an Documentation @@ -154,8 +174,10 @@ template = 0 [MySQL] # MySQL configuration +#default port: 3306 dbserver = localhost -dbuser = root +dbport = 3306 +dbuser = boswatch dbpassword = root database = boswatch diff --git a/citest/config.mysql.ini b/citest/config.mysql.ini index 7766f77..bad62e6 100644 --- a/citest/config.mysql.ini +++ b/citest/config.mysql.ini @@ -114,6 +114,26 @@ ricd = Unwetter # Usually sent periodically, separated by comma netIdent_ric = 0174760, 1398098 + +[multicastAlarm] +# Configure multicastAlarm if your POCSAG network uses an optimized transmission scheme for alarms with more than one RIC (often found in Swissphone networks). +# In this optimized transmission scheme, a POCSAG telegram with each RIC that needs to be alarmed will be send in a sequence. These telegrams are send without a text message. This sequence is directly followed by a telegram with a specific RIC and the text message that belongs to the sequnece send right before. +# A POCSAG pager (DME) can be configured to start an acoustic alarm if a specific RIC without text has been received. If afterwards the specific RIC with the text message will be received, the pager will show the message in it's display. +# multicastAlarm enables BOSwatch to process the all received RICs joined with the text message. +# +# enable multicastAlarm (0 - off | 1 - on) +multicastAlarm = 0 + +# time limit for alarms that do not belong to the multicastAlarm sequence in seconds +multicastAlarm_ignore_time = 15 + +# multicastAlarm delimiter RIC (usually used as a starting point for a alarm sequence) (can be empty) +multicastAlarm_delimiter_ric = + +# multicastAlarm RIC that is used to send the text message +multicastAlarm_ric = + + [Filters] # RegEX Filter Configuration # http://www.regexr.com/ - RegEX Test Tool an Documentation @@ -154,7 +174,9 @@ template = 0 [MySQL] # MySQL configuration +#default port: 3306 dbserver = localhost +dbport = 3306 dbuser = boswatch dbpassword = root database = boswatch diff --git a/citest/testdata.txt b/citest/testdata.txt index e4ac22e..4f1d5d1 100644 --- a/citest/testdata.txt +++ b/citest/testdata.txt @@ -35,7 +35,7 @@ POCSAG512: Address: 1000003 Function: 3 Alpha: BOSWatch-Test: okay POCSAG512: Address: 1200001 Function: 1 Alpha: BOSWatch-Test ÖÄÜß: okay POCSAG512: Address: 1200001 Function: 1 Alpha: BOSWatch-Test öäü: okay -# witch csv +# with csv POCSAG512: Address: 1234567 Function: 1 Alpha: BOSWatch-Test: with csv # without csv @@ -86,6 +86,22 @@ POCSAG1200: Address: 7777777 Function: 1 Alpha: BOSWatch-Test: denied POCSAG1200: Address: 0000004 Function: 1 Alpha: BOSWatch-Test: out of filter start POCSAG1200: Address: 9000000 Function: 1 Alpha: BOSWatch-Test: out of filter end +#Probealram +POCSAG1200: Address: 0871004 Function: 1 Alpha: Dies ist ein Probealarm! +## Multicast Alarm +POCSAG1200: Address: 0871002 Function: 0 Alpha: +POCSAG1200: Address: 0860001 Function: 0 +POCSAG1200: Address: 0860002 Function: 0 +POCSAG1200: Address: 0860003 Function: 0 +POCSAG1200: Address: 0860004 Function: 0 +POCSAG1200: Address: 0860005 Function: 0 +POCSAG1200: Address: 0860006 Function: 0 +POCSAG1200: Address: 0860007 Function: 0 +POCSAG1200: Address: 0860008 Function: 0 +POCSAG1200: Address: 0860009 Function: 0 +POCSAG1200: Address: 0860010 Function: 0 +POCSAG1200: Address: 0871003 Function: 0 Alpha: B2 Feuer Gebäude Pers in Gefahr. bla bla bla + # regEx-Filter? diff --git a/config/config.template.ini b/config/config.template.ini index 7a959f2..dd999a5 100644 --- a/config/config.template.ini +++ b/config/config.template.ini @@ -64,22 +64,6 @@ doubleFilter_check_msg = 0 writeMultimonRaw = 0 -[NMAHandler] -# you can use a logging handler for sending logging records to NotifyMyAndroid -# enableHandler (0|1) will enable the NMA handler -enableHandler = 0 - -# loglevel for NMAHandler (see BOSWatch loglevel description) -loglevel = 50 - -# logging record will send to APIKey -APIKey = - -# you can change the name of the application (default: BOSWatch) -# (f.e. if you use more than one instance of BOSWatch) -appName = BOSWatch - - [FMS] # look-up-table for adding a description # using description (0 - off | 1 - on) @@ -128,6 +112,27 @@ ricd = Unwetter # RIC for net identification # Usually sent periodically, separated by comma netIdent_ric = 0174760, 1398098 +# you can hold one entry per netIdent_ric [0] or the whole history [1] +netIdent_history = 0 + + +[multicastAlarm] +# Configure multicastAlarm if your POCSAG network uses an optimized transmission scheme for alarms with more than one RIC (often found in Swissphone networks). +# In this optimized transmission scheme, a POCSAG telegram with each RIC that needs to be alarmed will be send in a sequence. These telegrams are send without a text message. This sequence is directly followed by a telegram with a specific RIC and the text message that belongs to the sequnece send right before. +# A POCSAG pager (DME) can be configured to start an acoustic alarm if a specific RIC without text has been received. If afterwards the specific RIC with the text message will be received, the pager will show the message in it's display. +# multicastAlarm enables BOSwatch to process the all received RICs joined with the text message. +# +# enable multicastAlarm (0 - off | 1 - on) +multicastAlarm = 0 + +# time limit for alarms that do not belong to the multicastAlarm sequence in seconds +multicastAlarm_ignore_time = 15 + +# multicastAlarm delimiter RIC (usually used as a starting point for a alarm sequence). Needs to be empty if multicastAlarms are interrupted by normal alarms. +multicastAlarm_delimiter_ric = + +# multicastAlarm RIC that is used to send the text message +multicastAlarm_ric = [Filters] @@ -156,7 +161,6 @@ eMail = 0 BosMon = 0 firEmergency = 0 jsonSocket = 0 -notifyMyAndroid = 0 SMS = 0 Sms77 = 0 FFAgent = 0 @@ -170,7 +174,9 @@ template = 0 [MySQL] # MySQL configuration +#default port: 3306 dbserver = localhost +dbport = 3306 dbuser = boswatch dbpassword = root database = boswatch @@ -264,23 +270,6 @@ server = 192.168.0.1 port = 8888 -[notifyMyAndroid] -# APIKey given from notifyMyAndroid -APIKey = - -# Priority goes from -2 (lowest) to 2 (highest). The default priority is 0 (normal) -priority = 0 - -# You can change the name of the application (default: BOSWatch) -# (f.e. if you use more than one instance of BOSWatch) -appName = BOSWatch - -# instead of a given APIKey/priority you could import them by a csv-file (0|1) -# APIKey and priority above will be ignored, if you use a csv -# configuration loaded from csv/nma.csv -usecsv = 0 - - [SMS] # be aware that you need 'gammu' installed and running # at least you need an UMTS-stick which is supported by 'gammu' @@ -354,14 +343,24 @@ api_key = # Pushover Userkey or Groupkey to receive message user_key = -# Title of the message -title = BOSWatch Message - +# Section for POCSAG # Adapt Pocsag Subric (a,b,c,d) to Pushover Priorities (see https://pushover.net/api#priority) -SubA = 0 -SubB = 2 -SubC = 1 -SubD = 0 +SubA = 1 +SubB = 1 +SubC = 2 +SubD = -2 +poc_title = Alarm: %RIC%%LPAR%%FUNCCHAR%%RPAR% +poc_message = %DATE% %TIME% - %DESCR%: %MSG% + +# Section for ZVEI +zvei_prio = 1 +zvei_title = Alarm: %ZVEI% +zvei_message = %DATE% %TIME%: %ZVEI% + +# Section for FMS +fms_prio = 1 +fms_title = FMS: %FMS% +fms_message = %DATE% %TIME%: %FMS%%BR%Status: %STATUS% - Direction: %DIRT% - TSI: %TSI% %LPAR%%DESCR%%RPAR% # how often should Pushover re-alert in seconds (emergency-messages) retry = 30 @@ -453,6 +452,7 @@ test2 = 123456 # %RIC% = POCSAG RIC # %FUNC% = POCSAG function/Subric (1-4) # %FUNCCHAR% = POCSAG function/Subric als character (a-d) +# %FUNCTEXT% = POCSAG static Subric message (see [POC]) # %MSG% = Message of the POCSAG telegram # %BITRATE% = Bitrate of the POCSAG telegram # %DESCR% = Description, if description-module is used diff --git a/exampleAddOns/simpleWeb/mysql.class.php b/exampleAddOns/simpleWeb/mysql.class.php index 69d5fbd..a74b4b6 100644 --- a/exampleAddOns/simpleWeb/mysql.class.php +++ b/exampleAddOns/simpleWeb/mysql.class.php @@ -23,16 +23,16 @@ Simple Database Class (C) by Bastian Schroll function __construct($host, $user, $password, $database, $show_error = 1) { $this->show_error = $show_error; - @$this->conn = mysql_connect($host, $user, $password); + @$this->conn = mysqli_connect($host, $user, $password); if ($this->conn == false) { - $this->error("Keine Verbindung zum Datenbank Server!", mysql_error()); + $this->error("Keine Verbindung zum Datenbank Server!", mysqli_error($this->conn)); return false; } - if (!@mysql_select_db($database, $this->conn)) + if (!@mysqli_select_db($this->conn, $database)) { - $this->error("Datenbank nicht gefunden!", mysql_error()); + $this->error("Datenbank nicht gefunden!", mysqli_error($this->conn)); return false; } return true; @@ -41,17 +41,17 @@ Simple Database Class (C) by Bastian Schroll /** * Database::query() * - * F�hrt einen MySQL Query aus + * Fuehrt einen MySQL Query aus * - * @param mixed $query Auszuf�hrender Query + * @param mixed $query Auszufuehrender Query * @return Result-Handler/FALSE */ function query($query) { - $this->result = @mysql_query($query, $this->conn); + $this->result = @mysqli_query($this->conn, $query); if ($this->result == false) { - $this->error("Fehlerhafte Datenbank Anfrage!", mysql_error()); + $this->error("Fehlerhafte Datenbank Anfrage!", mysqli_error($this->conn)); return false; } return $this->result; @@ -60,51 +60,51 @@ Simple Database Class (C) by Bastian Schroll /** * Database::fetchAssoc() * - * Liefert alle gefundnen Datens�tze als Assoc + * Liefert alle gefundnen Datensaetze als Assoc * * @param mixed $result Externer Result-Handler - * @return gefundene Datens�tze als Assoc + * @return gefundene Datensaetze als Assoc */ function fetchAssoc($result = null) { if ($result != null) { - return @mysql_fetch_assoc($result); + return @mysqli_fetch_assoc($result); } else { - return @mysql_fetch_assoc($this->result); + return @mysqli_fetch_assoc($this->result); } } /** * Database::count() * - * Z�hlt alle gefundenen Datens�tze + * Zaehlt alle gefundenen Datensaetze * * @param mixed $result Externer Result-Handler - * @return Anzahl gefundener Datens�tze + * @return Anzahl gefundener Datensaetze */ function count($result = null) { if ($result != null) { - return @mysql_num_rows($result); + return @mysqli_num_rows($result); } else { - return @mysql_num_rows($this->result); + return @mysqli_num_rows($this->result); } } /** * Database::closeConnection() * - * Schlie�t die bestehende MySQL Verbindung + * Schliesst die bestehende MySQL Verbindung * * @return TRUE/FALSE */ function closeConnection() { - if (!@mysql_close($this->conn)) + if (!@mysqli_close($this->conn)) { $this->error("Verbindung zur Datenbank konnte nicht getrennt werden!", mysql_error()); return false; diff --git a/includes/NMAHandler.py b/includes/NMAHandler.py deleted file mode 100644 index 990e6f9..0000000 --- a/includes/NMAHandler.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/python -# -*- coding: UTF-8 -*- - -""" -Logging Handler for NotifyMyAndroid - -@author: Jens Herrmann -""" - -import logging -from includes.pynma import pynma - -class NMAHandler(logging.Handler): # Inherit from logging.Handler - """ - Handler instances dispatch logging events to NotifyMyAndroid. - """ - - def __init__(self, APIKey, application="BOSWatch", event="Logging-Handler"): - """ - Initializes the handler with NMA-specific parameters. - - @param APIKey: might be a string containing 1 key or an array of keys - @param application: application name [256] - @param event: event name [1000] - """ - # run the regular Handler __init__ - logging.Handler.__init__(self) - # Our custom argument - self.APIKey = APIKey - self.application = application - self.event = event - self.nma = pynma.PyNMA(self.APIKey) - - - def emit(self, record): - """ - Send logging record via NMA - """ - # record.message is the log message - message = record.message - - # if exist, add details as NMA event: - # record.module is the module- or filename - if (len(record.module) > 0): - event = "Module: " + record.module - # record.functionName is the name of the function - # will be "" if the message is not in a function - if len(record.funcName) > 0: - if not record.funcName == "": - event += " - " + record.funcName + "()" - else: - # we have to set an event-text, use self.event now - event = self.event - - # record.levelno is the log level - # loglevel: 10 = debug => priority: -2 - # loglevel: 20 = info => priority: -1 - # loglevel: 30 = warning => priority: 0 - # loglevel: 40 = error => priority: 1 - # loglevel: 50 = critical => priority: 2 - if record.levelno >= 50: - priority = 2 - elif record.levelno >= 40: - priority = 1 - elif record.levelno >= 30: - priority = 0 - elif record.levelno >= 20: - priority = -1 - else: - priority = -2 - - # pynma.push(self, application="", event="", description="", url="", contenttype=None, priority=0, batch_mode=False, html=False) - self.nma.push(application=self.application, event=event, description=message, priority=priority) diff --git a/includes/decoders/poc.py b/includes/decoders/poc.py index b0198f0..30a0e22 100644 --- a/includes/decoders/poc.py +++ b/includes/decoders/poc.py @@ -62,11 +62,23 @@ def isAllowed(poc_id): return True else: allowed = 0 + # 5.) Implementation for multicastAlarm + if globalVars.config.get("multicastAlarm", "multicastAlarm_delimiter_ric"): + if poc_id in globalVars.config.get("multicastAlarm", "multicastAlarm_delimiter_ric"): + logging.info("RIC %s as multicastAlarm delimiter", poc_id) + return True + else: + allowed = 0 + if globalVars.config.get("multicastAlarm", "multicastAlarm_ric"): + if poc_id in globalVars.config.get("multicastAlarm", "multicastAlarm_ric"): + logging.info("RIC %s as multicastAlarm message", poc_id) + return True + else: + allowed = 0 if allowed == 0: return False return True - ## # # POCSAG decoder function @@ -117,23 +129,40 @@ def decode(freq, decoded): if re.search("[0-9]{7}", poc_id) and re.search("[1-4]{1}", poc_sub): #if POC is valid if isAllowed(poc_id): + # check for double alarm if doubleFilter.checkID("POC", poc_id+poc_sub, poc_text): - logging.info("POCSAG%s: %s %s %s ", bitrate, poc_id, poc_sub, poc_text) data = {"ric":poc_id, "function":poc_sub, "msg":poc_text, "bitrate":bitrate, "description":poc_id} # Add function as character a-d to dataset data["functionChar"] = data["function"].replace("1", "a").replace("2", "b").replace("3", "c").replace("4", "d") + + logging.info("POCSAG%s: %s %s %s ", data["bitrate"], data["ric"], data["function"], data["msg"]) + # If enabled, look up description if globalVars.config.getint("POC", "idDescribed"): from includes import descriptionList - data["description"] = descriptionList.getDescription("POC", poc_id+data["functionChar"]) - # processing the alarm - try: - from includes import alarmHandler - alarmHandler.processAlarmHandler("POC", freq, data) - except: - logging.error("processing alarm failed") - logging.debug("processing alarm failed", exc_info=True) + data["description"] = descriptionList.getDescription("POC", data["ric"]+data["functionChar"]) + + # multicastAlarm processing if enabled and a message without text or delimiter RIC or netIdent_ric received + if globalVars.config.getint("multicastAlarm", "multicastAlarm") and data["ric"] != globalVars.config.get("POC", "netIdent_ric") and (data["msg"] == "" or data["ric"] in globalVars.config.get("multicastAlarm", "multicastAlarm_delimiter_ric")): + logging.debug(" - multicastAlarm without msg") + from includes import multicastAlarm + multicastAlarm.newEntrymultiList(data) + + # multicastAlarm processing if enabled and alarm message has been received + elif globalVars.config.getint("multicastAlarm", "multicastAlarm") and data["msg"] != "" and data["ric"] in globalVars.config.get("multicastAlarm", "multicastAlarm_ric"): + logging.debug(" - multicastAlarm with message") + from includes import multicastAlarm + multicastAlarm.multicastAlarmExec(freq, data) + + else: + # processing the alarm + try: + from includes import alarmHandler + alarmHandler.processAlarmHandler("POC", freq, data) + except: + logging.error("processing alarm failed") + logging.debug("processing alarm failed", exc_info=True) # in every time save old data for double alarm doubleFilter.newEntry(poc_id+poc_sub, poc_text) else: diff --git a/includes/globalVars.py b/includes/globalVars.py index be4305d..921975f 100644 --- a/includes/globalVars.py +++ b/includes/globalVars.py @@ -9,7 +9,7 @@ Global variables """ # version info -versionNr = "2.2.2" +versionNr = "2.4" branch = "dev" buildDate = "unreleased" diff --git a/includes/multicastAlarm.py b/includes/multicastAlarm.py new file mode 100644 index 0000000..8aafadd --- /dev/null +++ b/includes/multicastAlarm.py @@ -0,0 +1,65 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +""" +multicastAlarm is the function to enable BOSwatch to work in networks that optimise the transmission of POCSAG telegrams + +@author: Fabian Kessler + +@requires: Configuration has to be set in the config.ini +""" + +import logging # Global logger +import time # timestamp for multicastAlarm + +from includes import globalVars # Global variables + +# +# ListStructure [0..n] = (Data, TimeStamp) +# +multiList = [] + +def newEntrymultiList(data): + """ + add entry to multi alarm list and remove old entries + + @return: nothing + """ + global multiList + timestamp = int(time.time()) + # multicastAlarm processing if enabled and delimiter RIC has been received + if data['ric'] == globalVars.config.get("multicastAlarm", "multicastAlarm_delimiter_ric"): + del multiList[:] + logging.debug("delimiter RIC received - buffer cleared") + else: + multiList.append([data, timestamp]) + logging.debug("Added %s to multiList", data['ric']) + # check for old entries in multiList + for (xData, xTimestamp) in multiList[:]: + if xTimestamp < timestamp-globalVars.config.getint("multicastAlarm", "multicastAlarm_ignore_time"): + multiList.remove([xData, xTimestamp]) + logging.debug("RIC %s removed - %s sec. older than current timestamp", xData['ric'], xTimestamp-timestamp) + + +def multicastAlarmExec(freq, data): + """ + call alarmHandler for every entry in multiList + + @return: nothing + """ + logging.debug("data before update from multiList: %s", data) + for (xData, _) in multiList: + #update data with values multiList + data['ric'] = xData['ric'] + data['function'] = xData['function'] + data['functionChar'] = xData['functionChar'] + data['description'] = xData['description'] + logging.debug("data after update from multiList: %s", data) + try: + from includes import alarmHandler + alarmHandler.processAlarmHandler("POC", freq, data) + except: + logging.error("processing alarm failed") + logging.debug("processing alarm failed", exc_info=True) + del multiList[:] + logging.debug("multicastAlarm finished - buffer cleared") diff --git a/includes/pynma/README.md b/includes/pynma/README.md deleted file mode 100644 index e72ff1e..0000000 --- a/includes/pynma/README.md +++ /dev/null @@ -1,137 +0,0 @@ -Pynma -====== - -Pynma is a simple python module for the [NotifyMyAndroid][nma] [API][NMA API]. - -[nma]: http://nma.usk.bz/ -[NMA API]: http://nma.usk.bz/api.php - -Credits to: Damien Degois (github.com/babs) -Refactoring: Adriano Maia (adriano@usk.bz) - -[NotifyMyAndroid][nma] ---------------- -NotifyMyAndroid is a Prowl-like application for the Android. Notifications can be sent from your application Android device using push. NMA has an extensive API, which allows your scripts to integrate beautifully. (source: http://nma.usk.bz/) - -### How it works: -First, import the module: - - import pynma - -#### Keys management - -Create a PyNMA simple instance: - - p = pynma.PyNMA( "apikey(s)", "developerkey") - -A developerkey is optional. If you'd like to add just one API key, set it as string, if you want more, just provide a list of API key strings. - - p = pynma.PyNMA(['apikey1','apikey2']) # multiple API keys - p = pynma.PyNMA("apikey1","providerkey") # 1 API key with a providerkey - -For more flexible usage, you can add and remove keys: - - p.addkey("apikey1") - p.addkey(["apikey2","apikey3"]) - -Or set or change the providerkey - - p.developerkey("developerkey") - -#### Notification or Push or Add - - p.push(application, event, description, (opt) url, (opt) priority, (opt) batch mode) - -##### Application - -Application is your message generating application name (limited to 256) - -ex: my music player - -##### Event - -Event is the event name (limited to 1000) - -ex: switched to next track - -##### Description - -The description is the payload of your message (limited to 10000 (10k)) -ex: - - Playing next song, Blah Blah Blah - Artist: blah blah - Album: blah blah - Track: 18/24 - -##### Url - -The URL which should be attached to the notification. -This will trigger a redirect when on the user's device launched, and is viewable in the notification list. - -##### Priority - -Priority goes from -2 (lowest) to 2 (highest). the default priority is 0 (normal) - -##### Batch mode - -Batch mode is a boolean value to set if you'd like to push the same message to multiple API keys 5 by 5 (as the actual verion of prowl API allows you). This can reduce the number of call you make to the API which are limited. - -#### Return - -The push method returns a dict containing different values depending of the success of you call: - -##### The call succeed - -you'll have in the dict those keys: - - type: success - code: the HTTP like code (200 if success) - remaining: the number of API call you can to until the reset - resetdate: number of remaining minutes till the hourly reset of your API call limit - -##### The call failed - -For wathever reason, you call failed, the dict key "message" will contains the erro message returned by Prowl API. You'll find those keys: - - code: 400, 401, 402 or 500 (depends of the error kind) - message: API error message - -For the code description, please refer to [NMA API documentation][NMA API] for more informations - -##### The python module encountered an unhandled problem (mostly during parsing) - -The return keys will be: - - code: 600 - type: pynmaerror - message: the exception message - -Thanks ------- - -* **Cev** for URL integration and some fixes in docstring -* **ChaoticXSinZ** for UTF-8 integration and other typos - -License (MIT) -------------- - - Copyright (c) 2010-2011, Damien Degois. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. diff --git a/includes/pynma/__init__.py b/includes/pynma/__init__.py deleted file mode 100644 index 5df62d5..0000000 --- a/includes/pynma/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/python - -from .pynma import PyNMA diff --git a/includes/pynma/pynma.py b/includes/pynma/pynma.py deleted file mode 100644 index 5649f05..0000000 --- a/includes/pynma/pynma.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/python - -from xml.dom.minidom import parseString - -try: - from http.client import HTTPSConnection -except ImportError: - from httplib import HTTPSConnection - -try: - from urllib.parse import urlencode -except ImportError: - from urllib import urlencode - -__version__ = "1.0" - -API_SERVER = 'www.notifymyandroid.com' -ADD_PATH = '/publicapi/notify' - -USER_AGENT="PyNMA/v%s"%__version__ - -def uniq_preserve(seq): # Dave Kirby - # Order preserving - seen = set() - return [x for x in seq if x not in seen and not seen.add(x)] - -def uniq(seq): - # Not order preserving - return list({}.fromkeys(seq).keys()) - -class PyNMA(object): - """PyNMA(apikey=[], developerkey=None) -takes 2 optional arguments: - - (opt) apykey: might me a string containing 1 key or an array of keys - - (opt) developerkey: where you can store your developer key -""" - - def __init__(self, apikey=[], developerkey=None): - self._developerkey = None - self.developerkey(developerkey) - if apikey: - if isinstance(apikey, str): - apikey = [apikey] - self._apikey = uniq(apikey) - - def addkey(self, key): - "Add a key (register ?)" - if isinstance(key, str): - if not key in self._apikey: - self._apikey.append(key) - elif isinstance(key, list): - for k in key: - if not k in self._apikey: - self._apikey.append(k) - - def delkey(self, key): - "Removes a key (unregister ?)" - if isinstance(key, str): - if key in self._apikey: - self._apikey.remove(key) - elif isinstance(key, list): - for k in key: - if key in self._apikey: - self._apikey.remove(k) - - def developerkey(self, developerkey): - "Sets the developer key (and check it has the good length)" - if isinstance(developerkey, str) and len(developerkey) == 48: - self._developerkey = developerkey - - def pushWithAPIKey(self, apikey=[], application="", event="", description="", url="", contenttype=None, priority=0, batch_mode=False, html=False): - """Special Funktion""" - if apikey: - if isinstance(apikey, str): - apikey = [apikey] - self._apikey = uniq(apikey) - return self.push(application, event, description, url, contenttype, priority, batch_mode, html) - - def push(self, application="", event="", description="", url="", contenttype=None, priority=0, batch_mode=False, html=False): - """Pushes a message on the registered API keys. -takes 5 arguments: - - (req) application: application name [256] - - (req) event: event name [1000] - - (req) description: description [10000] - - (opt) url: url [512] - - (opt) contenttype: Content Type (act: None (plain text) or text/html) - - (opt) priority: from -2 (lowest) to 2 (highest) (def:0) - - (opt) batch_mode: push to all keys at once (def:False) - - (opt) html: shortcut for contenttype=text/html -Warning: using batch_mode will return error only if all API keys are bad - cf: http://nma.usk.bz/api.php -""" - datas = { - 'application': application[:256].encode('utf8'), - 'event': event[:1024].encode('utf8'), - 'description': description[:10000].encode('utf8'), - 'priority': priority - } - - if url: - datas['url'] = url[:512] - - if contenttype == "text/html" or html == True: # Currently only accepted content type - datas['content-type'] = "text/html" - - if self._developerkey: - datas['developerkey'] = self._developerkey - - results = {} - - if not batch_mode: - for key in self._apikey: - datas['apikey'] = key - res = self.callapi('POST', ADD_PATH, datas) - results[key] = res - else: - datas['apikey'] = ",".join(self._apikey) - res = self.callapi('POST', ADD_PATH, datas) - results[datas['apikey']] = res - return results - - def callapi(self, method, path, args): - headers = { 'User-Agent': USER_AGENT } - if method == "POST": - headers['Content-type'] = "application/x-www-form-urlencoded" - http_handler = HTTPSConnection(API_SERVER) - http_handler.request(method, path, urlencode(args), headers) - resp = http_handler.getresponse() - - try: - res = self._parse_reponse(resp.read()) - except Exception as e: - res = {'type': "pynmaerror", - 'code': 600, - 'message': str(e) - } - - return res - - def _parse_reponse(self, response): - root = parseString(response).firstChild - for elem in root.childNodes: - if elem.nodeType == elem.TEXT_NODE: continue - if elem.tagName == 'success': - res = dict(list(elem.attributes.items())) - res['message'] = "" - res['type'] = elem.tagName - return res - if elem.tagName == 'error': - res = dict(list(elem.attributes.items())) - res['message'] = elem.firstChild.nodeValue - res['type'] = elem.tagName - return res diff --git a/install.sh b/install.sh index 38a4530..5470b24 100644 --- a/install.sh +++ b/install.sh @@ -78,7 +78,6 @@ for (( i=1; i<=$#; i=$i+2 )); do -b|--branch) case $arg2 in dev|develop) echo " !!! WARNING: you are using the DEV BRANCH !!! "; branch=dev ;; - beta) echo " !!! WARNING: you are using the BETA BRANCH !!! "; branch=beta ;; *) branch=master ;; esac ;; @@ -213,7 +212,7 @@ echo "Installation ready!" tput cup 19 3 echo "Watch out: to run BOSWatch you have to modify the config.ini!" echo "Do the following step to do so:" -echo "sudo nano $boswatchpath/BOSWatch/config/config.ini" +echo "sudo nano $boswatchpath/config/config.ini" echo "and modify the config as you need. This step is optional if you are upgrading an old version of BOSWatch. " tput cnorm diff --git a/plugins/FFAgent/FFAgent.py b/plugins/FFAgent/FFAgent.py index 8dcff85..561ca86 100644 --- a/plugins/FFAgent/FFAgent.py +++ b/plugins/FFAgent/FFAgent.py @@ -132,9 +132,10 @@ def run(typ,freq,data): "selectiveCallCode": selectiveCallCode, "hmac": hmac.new(webApiKey, webApiToken + selectiveCallCode + accessToken + alarmData, digestmod=hashlib.sha256).hexdigest() } + logging.debug(alarmHeaders) if globalVars.config.get("FFAgent", "live") == "1": - r = requests.post(url, data=alarmData, headers=headers, verify=serverCertFile, cert=(clientCertFile, clientCertPass)) + r = requests.post(url, data=alarmData, headers=alarmHeaders, verify=serverCertFile, cert=(clientCertFile, clientCertPass)) else: r = requests.post(url, data=alarmData, headers=alarmHeaders, verify=serverCertFile) diff --git a/plugins/MySQL/MySQL.py b/plugins/MySQL/MySQL.py index e9d3d7e..c38410f 100644 --- a/plugins/MySQL/MySQL.py +++ b/plugins/MySQL/MySQL.py @@ -21,23 +21,23 @@ from includes import globalVars # Global variables from includes.helper import configHandler def isSignal(poc_id): - """ - @type poc_id: string - @param poc_id: POCSAG Ric + """ + @type poc_id: string + @param poc_id: POCSAG Ric - @requires: Configuration has to be set in the config.ini + @requires: Configuration has to be set in the config.ini - @return: True if the Ric is Signal, other False - @exception: none - """ - # If RIC is Signal return True, else False - if globalVars.config.get("POC", "netIdent_ric"): - if poc_id in globalVars.config.get("POC", "netIdent_ric"): - logging.info("RIC %s is net ident", poc_id) - return True - else: - logging.info("RIC %s is no net ident", poc_id) - return False + @return: True if the Ric is Signal, other False + @exception: none + """ + # If RIC is Signal return True, else False + if globalVars.config.get("POC", "netIdent_ric"): + if poc_id in globalVars.config.get("POC", "netIdent_ric"): + logging.info("RIC %s is net ident", poc_id) + return True + else: + logging.info("RIC %s is no net ident", poc_id) + return False ## @@ -91,7 +91,7 @@ def run(typ,freq,data): # Connect to MySQL # logging.debug("connect to MySQL") - connection = mysql.connector.connect(host = globalVars.config.get("MySQL","dbserver"), user = globalVars.config.get("MySQL","dbuser"), passwd = globalVars.config.get("MySQL","dbpassword"), db = globalVars.config.get("MySQL","database"), charset='utf8') + connection = mysql.connector.connect(host = globalVars.config.get("MySQL","dbserver"), port = globalVars.config.get("MySQL","dbport"), user = globalVars.config.get("MySQL","dbuser"), passwd = globalVars.config.get("MySQL","dbpassword"), db = globalVars.config.get("MySQL","database"), charset='utf8') cursor = connection.cursor() except: logging.error("cannot connect to MySQL") @@ -111,11 +111,14 @@ def run(typ,freq,data): elif typ == "POC": if isSignal(data["ric"]): - cursor.execute("UPDATE "+globalVars.config.get("MySQL","tableSIG")+" SET time = NOW() WHERE ric = '"+data["ric"]+"';") - if cursor.rowcount == 0: + if globalVars.config.getint("POC","netIdent_history"): cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableSIG")+" (time,ric) VALUES (NOW(), '"+data["ric"]+"');") + else: + cursor.execute("UPDATE "+globalVars.config.get("MySQL","tableSIG")+" SET time = NOW() WHERE ric = '"+data["ric"]+"';") + if cursor.rowcount == 0: + cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tableSIG")+" (time,ric) VALUES (NOW(), '"+data["ric"]+"');") else: - cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tablePOC")+" (time, ric, function, functionChar, msg, bitrate, description) VALUES (FROM_UNIXTIME(%s),%s,%s,%s,%s,%s,%s)", (data["timestamp"], data["ric"], data["function"], data["functionChar"], data["msg"], data["bitrate"], data["description"])) + cursor.execute("INSERT INTO "+globalVars.config.get("MySQL","tablePOC")+" (time, ric, function, functionChar, msg, bitrate, description) VALUES (FROM_UNIXTIME(%s),%s,%s,%s,%s,%s,%s)", (data["timestamp"], data["ric"], data["function"], data["functionChar"], data["msg"], data["bitrate"], data["description"])) else: logging.warning("Invalid Typ: %s", typ) diff --git a/plugins/Pushover/Pushover.py b/plugins/Pushover/Pushover.py index 1f97c95..d220de6 100644 --- a/plugins/Pushover/Pushover.py +++ b/plugins/Pushover/Pushover.py @@ -9,13 +9,15 @@ Pushover-Plugin to send FMS-, ZVEI- and POCSAG - messages to Pushover Clients @requires: Pushover-Configuration has to be set in the config.ini """ -import logging # Global logger -import httplib #for the HTTP request +import logging # Global logger +import httplib # for the HTTP request import urllib from includes import globalVars # Global variables -#from includes.helper import timeHandler +# from includes.helper import timeHandler from includes.helper import configHandler +from includes.helper import wildcardHandler + ## # @@ -23,16 +25,16 @@ from includes.helper import configHandler # will be called one time by the pluginLoader on start # def onLoad(): - """ - While loading the plugins by pluginLoader.loadPlugins() - this onLoad() routine is called one time for initialize the plugin + """ + While loading the plugins by pluginLoader.loadPlugins() + this onLoad() routine is called one time for initialize the plugin - @requires: nothing + @requires: nothing - @return: nothing - """ - # nothing to do for this plugin - return + @return: nothing + """ + # nothing to do for this plugin + return ## @@ -40,82 +42,112 @@ def onLoad(): # Main function of Pushover-plugin # will be called by the alarmHandler # -def run(typ,freq,data): - """ - This function is the implementation of the Pushover-Plugin. - It will send the data to Pushover API +def run(typ, freq, data): + """ + This function is the implementation of the Pushover-Plugin. + It will send the data to Pushover API - @type typ: string (FMS|ZVEI|POC) - @param typ: Typ of the dataset - @type data: map of data (structure see readme.md in plugin folder) - @param data: Contains the parameter - @type freq: string - @keyword freq: frequency of the SDR Stick + @type typ: string (FMS|ZVEI|POC) + @param typ: Typ of the dataset + @type data: map of data (structure see readme.md in plugin folder) + @param data: Contains the parameter + @type freq: string + @keyword freq: frequency of the SDR Stick - @requires: Pushover-Configuration has to be set in the config.ini + @requires: Pushover-Configuration has to be set in the config.ini - @return: nothing - """ - try: - if configHandler.checkConfig("Pushover"): #read and debug the config + @return: nothing + """ + try: + if configHandler.checkConfig("Pushover"): # read and debug the config - try: - # - # Pushover-Request - # - logging.debug("send Pushover %s", typ) + if typ == "FMS": + # + # building message for FMS + # - if data["function"] == '1': - priority = globalVars.config.get("Pushover", "SubA") - elif data["function"] == '2': - priority = globalVars.config.get("Pushover", "SubB") - elif data["function"] == '3': - priority = globalVars.config.get("Pushover", "SubC") - elif data["function"] == '4': - priority = globalVars.config.get("Pushover", "SubD") - else: - priority = 0 + message = globalVars.config.get("Pushover", "fms_message") + title = globalVars.config.get("Pushover", "fms_title") + priority = globalVars.config.get("Pushover", "fms_prio") + logging.debug("Sending message: %s", message) - conn = httplib.HTTPSConnection("api.pushover.net:443") - conn.request("POST", "/1/messages.json", - urllib.urlencode({ - "token": globalVars.config.get("Pushover", "api_key"), - "user": globalVars.config.get("Pushover", "user_key"), - "message": ""+data["description"]+"
"+data["msg"].replace(";", "
"), - "html": globalVars.config.get("Pushover", "html"), - "title": globalVars.config.get("Pushover", "title"), - "priority": priority, - "retry": globalVars.config.get("Pushover", "retry"), - "expire": globalVars.config.get("Pushover", "expire") - }),{"Content-type": "application/x-www-form-urlencoded"}) + elif typ == "ZVEI": + # + # building message for ZVEI + # + message = globalVars.config.get("Pushover", "zvei_message") + title = globalVars.config.get("Pushover", "zvei_title") + priority = globalVars.config.get("Pushover", "zvei_prio") + logging.debug("Sending message: %s", message) - except: - logging.error("cannot send Pushover request") - logging.debug("cannot send Pushover request", exc_info=True) - return + elif typ == "POC": - else: - try: - # - # check Pushover-Response - # - response = conn.getresponse() - if str(response.status) == "200": #Check Pushover Response and print a Log or Error - logging.debug("Pushover response: %s - %s" , str(response.status), str(response.reason)) - else: - logging.warning("Pushover response: %s - %s" , str(response.status), str(response.reason)) - except: #otherwise - logging.error("cannot get Pushover response") - logging.debug("cannot get Pushover response", exc_info=True) - return + # + # Pushover-Request + # + logging.debug("send Pushover for %s", typ) - finally: - logging.debug("close Pushover-Connection") - try: - request.close() - except: - pass + if data["function"] == '1': + priority = globalVars.config.get("Pushover", "SubA") + elif data["function"] == '2': + priority = globalVars.config.get("Pushover", "SubB") + elif data["function"] == '3': + priority = globalVars.config.get("Pushover", "SubC") + elif data["function"] == '4': + priority = globalVars.config.get("Pushover", "SubD") + else: + priority = 0 + message = globalVars.config.get("Pushover", "poc_message") + title = globalVars.config.get("Pushover", "poc_title") - except: - logging.error("unknown error") - logging.debug("unknown error", exc_info=True) + else: + logging.warning("Invalid type: %s", typ) + + try: + # replace the wildcards + message = wildcardHandler.replaceWildcards(message, data) + title = wildcardHandler.replaceWildcards(title, data) + + # start the connection + conn = httplib.HTTPSConnection("api.pushover.net:443") + conn.request("POST", "/1/messages.json", + urllib.urlencode({ + "token": globalVars.config.get("Pushover", "api_key"), + "user": globalVars.config.get("Pushover", "user_key"), + "message": message, + "html": globalVars.config.get("Pushover", "html"), + "title": title, + "priority": priority, + "retry": globalVars.config.get("Pushover", "retry"), + "expire": globalVars.config.get("Pushover", "expire") + }), {"Content-type": "application/x-www-form-urlencoded"}) + + except: + logging.error("cannot send Pushover request") + logging.debug("cannot send Pushover request", exc_info=True) + return + + try: + # + # check Pushover-Response + # + response = conn.getresponse() + if str(response.status) == "200": # Check Pushover Response and print a Log or Error + logging.debug("Pushover response: %s - %s", str(response.status), str(response.reason)) + else: + logging.warning("Pushover response: %s - %s", str(response.status), str(response.reason)) + except: # otherwise + logging.error("cannot get Pushover response") + logging.debug("cannot get Pushover response", exc_info=True) + return + + finally: + logging.debug("close Pushover-Connection") + try: + request.close() + except: + pass + + except: + logging.error("unknown error") + logging.debug("unknown error", exc_info=True) diff --git a/plugins/firEmergency/firEmergency.py b/plugins/firEmergency/firEmergency.py index a724cd2..89a325c 100644 --- a/plugins/firEmergency/firEmergency.py +++ b/plugins/firEmergency/firEmergency.py @@ -5,7 +5,7 @@ firEmergency-Plugin to dispatch ZVEI- and POCSAG - messages to firEmergency firEmergency configuration: -- set input to "FMS32" at Port 5555 +- set input to "Standartschnittstelle" at Port 5555 @autor: Smith-fms diff --git a/plugins/httpRequest/httpRequest.py b/plugins/httpRequest/httpRequest.py index 56e35a6..1622a8b 100644 --- a/plugins/httpRequest/httpRequest.py +++ b/plugins/httpRequest/httpRequest.py @@ -68,11 +68,13 @@ def run(typ,freq,data): try: # - # Replace special characters in data Strings for URL + # Make a copy of the data field to not overwrite the data in it + # Replace special characters in dataCopy Strings for URL # - for key in data: - if isinstance(data[key], basestring): - data[key] = urllib.quote(data[key]) + dataCopy = dict(data) + for key in dataCopy: + if isinstance(dataCopy[key], basestring): + dataCopy[key] = urllib.quote(dataCopy[key]) # # Get URLs # @@ -90,7 +92,7 @@ def run(typ,freq,data): # replace wildcards # for (i, url) in enumerate(urls): - urls[i] = wildcardHandler.replaceWildcards(urls[i].strip(), data) + urls[i] = wildcardHandler.replaceWildcards(urls[i].strip(), dataCopy) # # HTTP-Request # diff --git a/plugins/notifyMyAndroid/notifyMyAndroid.py b/plugins/notifyMyAndroid/notifyMyAndroid.py deleted file mode 100644 index a8ab127..0000000 --- a/plugins/notifyMyAndroid/notifyMyAndroid.py +++ /dev/null @@ -1,301 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- - -""" -notifyMyAndroid-Plugin to dispatch FMS-, ZVEI- and POCSAG-messages via UDP/TCP - -@author: Jens Herrmann - -@requires: notifyMyAndroid-Configuration has to be set in the config.ini -""" - -import logging # Global logger -import csv # for loading the APIKeys - - -from includes import globalVars # Global variables - -from includes.helper import configHandler -from includes.helper import timeHandler -from includes.helper import stringConverter -from includes.pynma import pynma - - -# local variables -application = "BOSWatch" -APIKey = None -remainingMsgs = None -usecsv = False -# data structures: xAPIKeyList[id][i] = (APIKey, priority, eventPrefix) -fmsAPIKeyList = {} -zveiAPIKeyList = {} -pocAPIKeyList = {} - - -def checkResponse(response, APIKey): - """ - Helper function to check the response of NMA - - @type response: dict - @param response: Response of the pyNMA.push() method - @type data: string / array - @param data: a string containing 1 key or an array of keys - - @return: nothing - """ - # local variables - global remainingMsgs - try: - # - # check HTTP-Response - # - if str(response[APIKey]['code']) == "200": #Check HTTP Response an print a Log or Error - logging.debug("NMA response: %s" , str(response[APIKey]['code'])) - remainingMsgs = response[APIKey]['remaining'] - if int(remainingMsgs) == 0: - logging.error("NMA remaining msgs: %s" , str(remainingMsgs)) - if int(response[APIKey]['remaining']) < 20: - logging.warning("NMA remaining msgs: %s" , str(remainingMsgs)) - else: - logging.debug("NMA remaining msgs: %s" , str(remainingMsgs)) - else: - logging.warning("NMA response: %s - %s" , str(response[APIKey]['code']), str(response[APIKey]['message'])) - except: - logging.error("cannot read pynma response") - logging.debug("cannot read pynma response", exc_info=True) - return - - -## -# -# onLoad (init) function of plugin -# will be called one time by the pluginLoader on start -# -def onLoad(): - """ - While loading the plugins by pluginLoader.loadPlugins() - this onLoad() routine is called one time for initialize the plugin - - @requires: nothing - - @return: nothing - """ - # local variables - global application - global APIKey - global usecsv - - # load config: - configHandler.checkConfig("notifyMyAndroid") - application = stringConverter.convertToUnicode(globalVars.config.get("notifyMyAndroid","appName")) - usecsv = globalVars.config.getboolean("notifyMyAndroid","usecsv") - - # if no csv should use, we take the APIKey directly - if usecsv == False: - APIKey = globalVars.config.get("notifyMyAndroid","APIKey") - else: - # import the csv-file - try: - logging.debug("-- loading nma.csv") - with open(globalVars.script_path+'/csv/nma.csv') as csvfile: - # DictReader expected structure described in first line of csv-file - reader = csv.DictReader(csvfile) - for row in reader: - logging.debug(row) - # only import rows with an supported types - supportedTypes = ["FMS", "ZVEI", "POC"] - if row['typ'] in supportedTypes: - try: - if "FMS" in row['typ']: - # if len for id in mainList raise an KeyErrorException, we have to init it... - try: - if len(fmsAPIKeyList[row['id']]) > 0: - pass - except KeyError: - fmsAPIKeyList[row['id']] = [] - # data structure: fmsAPIKeyList[fms][i] = (APIKey, priority) - fmsAPIKeyList[row['id']].append((row['APIKey'], row['priority'], row['eventPrefix'])) - - elif "ZVEI" in row['typ']: - # if len for id in mainList raise an KeyErrorException, we have to init it... - try: - if len(zveiAPIKeyList[row['id']]) > 0: - pass - except KeyError: - zveiAPIKeyList[row['id']] = [] - # data structure: zveiAPIKeyList[zvei][i] = (APIKey, priority) - zveiAPIKeyList[row['id']].append((row['APIKey'], row['priority'], row['eventPrefix'])) - - elif "POC" in row['typ']: - # if len for id in mainList raise an KeyErrorException, we have to init it... - try: - if len(pocAPIKeyList[row['id']]) > 0: - pass - except KeyError: - pocAPIKeyList[row['id']] = [] - # data structure: zveiAPIKeyList[ric][i] = (APIKey, priority) - pocAPIKeyList[row['id']].append((row['APIKey'], row['priority'], row['eventPrefix'])) - - except: - # skip entry in case of an exception - logging.debug("error in shifting...", exc_info=True) - # if row['typ'] in supportedTypes - # for row in reader: - logging.debug("-- loading csv finished") - except: - logging.error("loading csvList for nma failed") - logging.debug("loading csvList for nma failed", exc_info=True) - raise - # and if usecsv == True - return - - -## -# -# Main function of jsonSocket-plugin -# will be called by the alarmHandler -# -def run(typ,freq,data): - """ - This function is the implementation of the notifyMyAndroid-Plugin. - - The configuration is set in the config.ini. - - @type typ: string (FMS|ZVEI|POC) - @param typ: Typ of the dataset for sending via UDP/TCP - @type data: map of data (structure see readme.md in plugin folder) - @param data: Contains the parameter for dispatch to UDP. - @type freq: string - @keyword freq: frequency of the SDR Stick - - @requires: notifyMyAndroid-Configuration has to be set in the config.ini - - @return: nothing - """ - # local variables - - try: - try: - # - # initialize to pyNMA - # - nma = pynma.PyNMA() - except: - logging.error("cannot initialize pyNMA") - logging.debug("cannot initialize pyNMA", exc_info=True) - # Without class, plugin couldn't work - return - - else: - # toDo is equals for all types, so only check if typ is supported - supportedTypes = ["FMS", "ZVEI", "POC"] - if typ in supportedTypes: - logging.debug("Start %s to NMA", typ) - try: - # build event and msg - # pyNMA expect strings are not in UTF-8 - event = stringConverter.convertToUnicode(data['description']) - msg = timeHandler.getDateTime(data['timestamp']) - if ("POC" in typ) and (len(data['msg']) > 0): - msg += "\n" + data['msg'] - msg = stringConverter.convertToUnicode(msg) - - # if not using csv-import, all is simple... - if usecsv == False: - response = nma.pushWithAPIKey(APIKey, application, event, msg, priority=globalVars.config.getint("notifyMyAndroid","priority")) - checkResponse(response, APIKey) - else: - if "FMS" in typ: - # lets look for fms in fmsAPIKeyList - xID = data['fms'] - try: - # data structure: fmsAPIKeyList[xID][i] = (xAPIKey, xPriority, xEventPrefix) - for i in range(len(fmsAPIKeyList[xID])): - xEvent = event - (xAPIKey, xPriority, xEventPrefix) = fmsAPIKeyList[xID][i] - if len(xEventPrefix) > 0: - xEvent = xEventPrefix + ": " + xEvent - response = nma.pushWithAPIKey(xAPIKey, application, xEvent, msg, priority=xPriority) - checkResponse(response, xAPIKey) - except KeyError: - # nothing found - pass - - elif "ZVEI" in typ: - # lets look for zvei in zveiAPIKeyList - xID = data['zvei'] - try: - # data structure: zveiAPIKeyList[xID][i] = (xAPIKey, xPriority, xEventPrefix) - for i in range(len(zveiAPIKeyList[xID])): - xEvent = event - (xAPIKey, xPriority, xEventPrefix) = zveiAPIKeyList[xID][i] - if len(xEventPrefix) > 0: - xEvent = xEventPrefix + ": " + xEvent - response = nma.pushWithAPIKey(xAPIKey, application, xEvent, msg, priority=xPriority) - checkResponse(response, xAPIKey) - except KeyError: - # nothing found - pass - - elif "POC" in typ: - xID = "" - # 1. lets look for ric+functionChar in pocAPIKeyList - try: - xID = data['ric'] + data['functionChar'] - # data structure: pocAPIKeyList[xID][i] = (xAPIKey, xPriority, xEventPrefix) - for i in range(len(pocAPIKeyList[xID])): - xEvent = event - (xAPIKey, xPriority, xEventPrefix) = pocAPIKeyList[xID][i] - if len(xEventPrefix) > 0: - xEvent = xEventPrefix + ": " + xEvent - response = nma.pushWithAPIKey(xAPIKey, application, xEvent, msg, priority=xPriority) - checkResponse(response, xAPIKey) - except KeyError: - # nothing found - pass - # 2. lets look for ric* in pocAPIKeyList - try: - xID = data['ric'] + "*" - # data structure: pocAPIKeyList[xID][i] = (xAPIKey, xPriority, xEventPrefix) - for i in range(len(pocAPIKeyList[xID])): - xEvent = event - (xAPIKey, xPriority, xEventPrefix) = pocAPIKeyList[xID][i] - if len(xEventPrefix) > 0: - xEvent = xEventPrefix + ": " + xEvent - response = nma.pushWithAPIKey(xAPIKey, application, xEvent, msg, priority=xPriority) - checkResponse(response, xAPIKey) - except KeyError: - # nothing found - pass - # 3. lets look for ric prefixes in pocAPIKeyList - for prefixLength in reversed(range(6)): - ricPrefix = data['ric'][:prefixLength] - #fill the ric with stars - ricPrefix = ricPrefix.ljust(8,'*') - try: - xID = ricPrefix - # data structure: pocAPIKeyList[xID][i] = (xAPIKey, xPriority, xEventPrefix) - for i in range(len(pocAPIKeyList[xID])): - xEvent = event - (xAPIKey, xPriority, xEventPrefix) = pocAPIKeyList[xID][i] - if len(xEventPrefix) > 0: - xEvent = xEventPrefix + ": " + xEvent - response = nma.pushWithAPIKey(xAPIKey, application, xEvent, msg, priority=xPriority) - checkResponse(response, xAPIKey) - except KeyError: - # nothing found - pass - - # end if "POC" in typ - # end if usecsv == True - except: - logging.error("%s to NMA failed", typ) - logging.debug("%s to NMA failed", typ, exc_info=True) - return - else: - logging.warning("Invalid Typ: %s", typ) - - except: - # something very mysterious - logging.error("unknown error") - logging.debug("unknown error", exc_info=True)