telegram-notify/telegram-notify-daemon

336 lines
10 KiB
Plaintext
Raw Normal View History

2017-12-28 22:48:05 +00:00
#!/usr/bin/env python2
2017-12-26 10:59:09 +00:00
import time
import random
import datetime
import re
import ConfigParser
import telepot
2017-12-26 18:29:54 +00:00
import json
2017-12-26 21:33:49 +00:00
import sys
2017-12-27 21:44:11 +00:00
import os
import argparse
2018-01-14 21:01:01 +00:00
import logging
2018-01-15 20:58:15 +00:00
import atexit
2018-01-15 21:11:23 +00:00
import signal
2017-12-26 10:59:09 +00:00
from telepot.loop import MessageLoop
2017-12-27 21:44:11 +00:00
from watchdog.observers import Observer
from watchdog.events import PatternMatchingEventHandler
2017-12-26 10:59:09 +00:00
2017-12-26 21:33:49 +00:00
version = 0.1
2017-12-26 10:59:09 +00:00
2018-01-14 21:01:01 +00:00
2017-12-26 10:59:09 +00:00
def writeconfig():
2018-01-14 21:01:01 +00:00
if not os.access(configFile, os.W_OK):
print 'WARNING: Config file (%s) is not writable ...' % configFile
logger.warning('Config file (%s) is not writable ...' % configFile)
return False
with open(configFile, 'wb') as theFile:
configParser.write(theFile)
logger.info('Config file (%s) updated ...' % configFile)
2017-12-26 10:59:09 +00:00
def handle(msg):
global configParser
2017-12-26 18:29:54 +00:00
global chat_ids
2017-12-26 10:59:09 +00:00
pair_pin = configParser.get('general', 'pair_pin')
chat_id = msg['chat']['id']
2017-12-26 18:29:54 +00:00
username = msg['chat']['username']
firstname = msg['chat']['first_name']
lastname = msg['chat']['last_name']
2017-12-26 10:59:09 +00:00
command = msg['text']
param = ''
2017-12-26 18:29:54 +00:00
paired_user = [x for x in chat_ids if x['id'] == chat_id]
2017-12-26 10:59:09 +00:00
is_paired = len(paired_user) > 0
2017-12-26 21:33:49 +00:00
# if text starts with '/' then it's a command
2017-12-27 21:44:11 +00:00
if re.match(r'^/',msg['text']):
2017-12-26 10:59:09 +00:00
command = re.sub(r"\s.*",'',msg['text'])
param = re.sub(r"^([^\s]+)\s","",msg['text'])
2017-12-26 18:29:54 +00:00
print '\n\nUser %s sent command: %s (%s)' % (username, command, param)
2017-12-26 10:59:09 +00:00
if command == '/pair':
if is_paired:
bot.sendMessage(chat_id, 'You\'re already paired.')
elif param == pair_pin:
2017-12-26 18:29:54 +00:00
chat={
'username': username,
'firstname': firstname,
'lastname': lastname,
'id': chat_id
}
chat_ids.append(chat)
section = 'id-' + str(chat_id)
if not configParser.has_section(section):
configParser.add_section(section)
configParser.set(section, 'username', username)
configParser.set(section, 'firstname', firstname)
configParser.set(section, 'lastname', lastname)
2017-12-26 10:59:09 +00:00
writeconfig()
bot.sendMessage(chat_id, 'Pairing ok.')
else:
bot.sendMessage(chat_id, 'Pairing failed: wrong pin.')
2017-12-26 18:29:54 +00:00
2017-12-26 10:59:09 +00:00
elif command == '/newpin':
if not is_paired:
bot.sendMessage(chat_id, 'You\'re not allowed to do that. You have to pair first.')
elif param != '':
pair_pin = param
configParser.set('general', 'pair_pin', pair_pin)
writeconfig()
bot.sendMessage(chat_id, 'The new pin is: %s' % pair_pin)
else:
bot.sendMessage(chat_id, 'Please specify the new pin.')
2017-12-26 18:29:54 +00:00
2017-12-26 10:59:09 +00:00
elif command == '/unpair':
if not is_paired:
bot.sendMessage(chat_id, 'You\'re not allowed to do that. You have to pair first.')
else:
2017-12-26 18:29:54 +00:00
chat_ids[:] = [x for x in chat_ids if x['id'] != chat_id]
section = 'id-' + str(chat_id)
configParser.remove_section(section)
writeconfig()
2017-12-26 10:59:09 +00:00
bot.sendMessage(chat_id, 'Bye.')
2017-12-26 18:29:54 +00:00
2017-12-26 10:59:09 +00:00
elif command == '/users':
2017-12-26 18:29:54 +00:00
if not is_paired:
bot.sendMessage(chat_id, 'You\'re not allowed to do that. You have to pair first.')
else:
users = [x['username'] + ' (' + x['firstname'] + ' ' + x['lastname'] + ')\n' for x in chat_ids]
bot.sendMessage(chat_id, 'Paired users:\n' + "".join([str(i) for i in users]) )
2017-12-26 10:59:09 +00:00
2017-12-26 21:33:49 +00:00
elif command == '/start':
bot.sendMessage(chat_id, 'Started:\n' )
elif command == '/help':
bot.sendMessage(chat_id, 'Help:\n' )
elif command == '/settings':
bot.sendMessage(chat_id, 'Settings:\n' )
2017-12-27 21:44:11 +00:00
def processFile(filename):
2018-01-14 21:01:01 +00:00
logger.info('Processing %s' % filename)
2018-01-15 20:45:51 +00:00
if re.match(r'.*jpe?g$',filename):
2017-12-27 21:44:11 +00:00
for c in chat_ids:
try:
2018-01-15 21:34:25 +00:00
logger.info('sending %s as picture to %s' % (filename,c['username']))
2017-12-27 21:44:11 +00:00
r=bot.sendPhoto(c['id'], open(filename, 'rb'))
os.remove(filename)
2018-01-14 21:01:01 +00:00
logger.debug('removed %s' % filename)
2017-12-27 21:44:11 +00:00
except:
time.sleep(10)
if re.match(r'.*txt$',filename):
for c in chat_ids:
try:
with open(filename,'r') as f:
2018-01-15 21:34:25 +00:00
logger.info('sending %s as text to %s' % (filename,c['username']))
2017-12-27 21:44:11 +00:00
r=bot.sendMessage(c['id'], f.read())
os.remove(filename)
2018-01-14 21:01:01 +00:00
logger.debug('removed %s' % filename)
2017-12-27 21:44:11 +00:00
except:
time.sleep(10)
class FilesChangedHandler(PatternMatchingEventHandler):
patterns = ["*.jpg", "*.txt"]
def process(self, event):
"""
event.event_type
'modified' | 'created' | 'moved' | 'deleted'
event.is_directory
True | False
event.src_path
path/to/observed/file
"""
if event.event_type=='created':
processFile(event.src_path)
def on_modified(self, event):
self.process(event)
def on_created(self, event):
self.process(event)
def checkFiles():
2018-01-14 21:01:01 +00:00
spool_dir = configParser.get('general', 'spool_dir')
2018-01-15 21:34:25 +00:00
logger.debug('Checking %s for new files ...' % spool_dir)
2017-12-27 21:44:11 +00:00
l=os.listdir(spool_dir)
for f in l:
processFile("%s/%s" % (spool_dir,f) )
2017-12-26 21:33:49 +00:00
2018-01-15 21:11:23 +00:00
def initSignals():
signal.signal(signal.SIGINT, exitGracefully)
signal.signal(signal.SIGTERM, exitGracefully)
def exitGracefully(signum, frame):
global shutdown
shutdown = True
2018-01-15 21:13:06 +00:00
2018-01-14 21:01:01 +00:00
def setDefaults():
global configFile
global defaults
configFile = '/etc/telegram-notify/telegram-notify.conf'
if not os.path.isfile(configFile) or not os.access(configFile, os.R_OK):
2018-01-14 21:01:01 +00:00
configFile = './telegram-notify.conf'
if not os.path.isfile(configFile) or not os.access(configFile, os.R_OK):
configFile = ''
logFile = '/var/log/telegram-notify.log'
if not os.path.isfile(logFile) or not os.access(logFile, os.W_OK):
logFile = ''
defaults = {
'log_file': logFile,
'log_level': 'info',
'daemon': False,
'token': '',
'pair_pin': '1234',
2018-01-15 20:58:15 +00:00
'spool_dir': '/var/spool/telegram-notify',
'pid_file': '/var/run/telegram-notify/telegram-notify.pid'
2018-01-14 21:01:01 +00:00
}
def parseCmdLine():
global configFile
parser = argparse.ArgumentParser(description='Daemon for Telegram notification management')
parser.add_argument('-c', '--config', nargs='?',
help='start with specified config file (default: telegram-notify.conf in /etc/ or in current directory)')
parser.add_argument('-V', '--version', action='store_true',
help='show program version and quit')
args = parser.parse_args()
if args.version:
2018-01-15 20:45:51 +00:00
print 'telegram-notify-daemon version %s - Copyright (C) 2018 by Paolo Asperti.' % version
2018-01-14 21:01:01 +00:00
sys.exit(0)
if args.config:
if not os.path.isfile(args.config):
print 'specified config file doesn\'t exists or is not a file'
sys.exit(1)
if not os.access(args.config, os.R_OK):
print 'specified config file is not readable'
sys.exit(1)
configFile = args.config
def readConfigFile():
global configParser
if configFile == '':
print 'no config file available'
sys.exit(1)
2018-01-14 21:01:01 +00:00
if not os.access(configFile, os.W_OK):
print 'WARNING: specified config file is not writable'
2018-01-14 21:01:01 +00:00
configParser = ConfigParser.SafeConfigParser(defaults=defaults)
configParser.read(configFile)
2018-01-14 21:01:01 +00:00
def initLogger():
global logger
logFile = configParser.get('general', 'log_file')
if logFile == '':
print 'no log file available'
sys.exit(1)
2018-01-14 21:01:01 +00:00
logLevel = configParser.get('general', 'log_level')
logging.basicConfig(filename=logFile,level=logLevel,format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
2018-01-15 21:13:06 +00:00
2018-01-15 20:58:15 +00:00
def checkPIDFile():
PIDFile = configParser.get('general', 'pid_file')
try:
pf = open(PIDFile,'r')
pid = int(pf.read().strip())
pf.close()
except (IOError, TypeError):
pid = None
if pid:
logger.error('pidfile %s already exist. Daemon already running?' % PIDFile)
sys.stderr.write('pidfile %s already exist. Daemon already running?' % PIDFile)
sys.exit(1)
atexit.register(delPIDFile)
open(PIDFile,'w+').write("%s\n" % str(os.getpid()))
logger.info('Created PIDfile %s' % PIDFile)
2018-01-15 21:11:03 +00:00
2018-01-15 20:58:15 +00:00
def delPIDFile():
PIDFile = configParser.get('general', 'pid_file')
os.remove(PIDFile)
logger.info('Removed PIDfile %s' % PIDFile)
2017-12-26 21:33:49 +00:00
2018-01-15 21:11:03 +00:00
2018-01-14 21:01:01 +00:00
def checkSpoolDir():
spool_dir = configParser.get('general', 'spool_dir')
if not os.path.isdir(spool_dir):
print "spool directory (%s) doesn't exists or is not a directory!" % spool_dir
sys.exit(1)
2017-12-26 10:59:09 +00:00
2018-01-14 21:01:01 +00:00
if not os.access(spool_dir, os.W_OK):
print "spool directory (%s) is not writable!" % spool_dir
sys.exit(1)
2017-12-26 18:29:54 +00:00
2018-01-14 21:01:01 +00:00
def initBot():
global bot
global chat_ids
chat_ids=[]
2018-01-15 21:11:03 +00:00
logger.debug('Allowed users:')
2018-01-14 21:01:01 +00:00
for p in configParser.sections():
if re.match('^id-.*',p):
chat_id={
'username': configParser.get(p,'username'),
'firstname': configParser.get(p,'firstname'),
'lastname': configParser.get(p,'lastname'),
'id': int(re.sub(r'^id-','',p))
}
chat_ids.append(chat_id)
logger.debug(" - (%s) %s %s" % (chat_id['username'],chat_id['firstname'],chat_id['lastname']) )
2017-12-27 21:44:11 +00:00
2018-01-14 21:01:01 +00:00
token = configParser.get('general', 'token')
bot = telepot.Bot(token)
2017-12-26 10:59:09 +00:00
2018-01-14 21:01:01 +00:00
MessageLoop(bot, handle).run_as_thread()
logger.info('Loop started. I am listening ...')
2017-12-26 10:59:09 +00:00
2018-01-14 21:01:01 +00:00
checkFiles()
spool_dir = configParser.get('general', 'spool_dir')
observer = Observer()
observer.schedule(FilesChangedHandler(), path=spool_dir)
observer.start()
2017-12-26 10:59:09 +00:00
2018-01-15 21:13:06 +00:00
2018-01-15 21:11:23 +00:00
initSignals()
2018-01-14 21:01:01 +00:00
setDefaults()
parseCmdLine()
readConfigFile()
initLogger()
2018-01-15 20:58:15 +00:00
checkPIDFile()
2018-01-14 21:01:01 +00:00
checkSpoolDir()
initBot()
2017-12-27 21:44:11 +00:00
2018-01-14 21:01:01 +00:00
daemon = configParser.get('general', 'daemon')
2017-12-27 21:44:11 +00:00
2018-01-15 21:11:23 +00:00
shutdown = False
2017-12-26 10:59:09 +00:00
while 1:
2017-12-27 21:44:11 +00:00
checkFiles()
2018-01-14 21:01:01 +00:00
if re.match('false', daemon, re.IGNORECASE):
sys.exit(0)
2018-01-15 21:11:23 +00:00
for x in range(0, 40):
if shutdown:
logger.info('Daemon shutdown requested. Exiting...')
sys.exit(0)
time.sleep(0.25)