Merge branch 'dev' of drymer/jabbergram into master

This commit is contained in:
drymer 2017-07-21 08:29:37 +02:00 committed by git
commit 2b47e3528d
7 changed files with 111 additions and 68 deletions

View File

@ -48,7 +48,7 @@ Install via pip:
Clone the repository: Clone the repository:
$ git clone git://daemons.cf/jabbergram $ git clone https://git.daemons.it/drymer/jabbergram
$ cd jabbergram $ cd jabbergram
$ su -c "pip3 install -r requirements.txt" $ su -c "pip3 install -r requirements.txt"
$ su -c "python3 setup.py install" $ su -c "python3 setup.py install"
@ -128,9 +128,9 @@ Instalar a través de `pip`:
Clonar el repositorio: Clonar el repositorio:
$ git clone git://daemons.cf/jabbergram $ git clone https://git.daemons.it/drymer/jabbergram
$ cd jabbergram $ cd jabbergram
$ su -c "pip3 instalar -r requirements.txt" $ su -c "pip3 install -r requirements.txt"
$ su -c "python3 setup.py install" $ su -c "python3 setup.py install"
### Configuración<a id="orgheadline9"></a> ### Configuración<a id="orgheadline9"></a>
@ -145,7 +145,7 @@ Este programa es simple, no tiene ni un menú de `ayuda`. Lo primero que hay que
NombreDelBot NombreDelBot
# Ahora hay que pulsar desactivar # Ahora hay que pulsar desactivar
La opción `/setprivacy` es para hacer que el robot pueda leer todo lo que se dice en el grupo, no sólo cuando se utilizan los comandos. Es necesario para hacer que `jabbergram` funcione. Más información sobre la creación los bots de `Telegrama` en su [página web](https://core.telegram.org/bots). La opción `/setprivacy` es para hacer que el robot pueda leer todo lo que se dice en el grupo, no sólo cuando se utilizan los comandos. Es necesario para hacer que `jabbergram` funcione. Más información sobre la creación los bots de `Telegram` en su [página web](https://core.telegram.org/bots).
A continuación, hay que crear un archivo de configuración, que llamaremos `config.ini`. En ese archivo, introduce los siguientes parámetros: A continuación, hay que crear un archivo de configuración, que llamaremos `config.ini`. En ese archivo, introduce los siguientes parámetros:
@ -173,7 +173,7 @@ Sólo puede haber un archivo de configuración. Esto es debido a que sólo puede
token = jabbergramBotTokken token = jabbergramBotTokken
group = -10293943920 120301203 group = -10293943920 120301203
De este modo, el muc "exampleMuc@muc.nope.org" se sincronizará con el grupo "-10293943920", y "segunda@muc.sip.org" con "120301203". De este modo, el muc "exampleMuc@muc.nope.org" se sincronizará con el grupo "-10293943920", y "segunda@muc.sip.org" con "120301203". Hecho esto, solo queda ejecutarlo en la terminal: `python3 jabbergram.py config.ini`. Hay que tenerla activa siempre que se quiera que funcione, obviamente.
### Licencia<a id="orgheadline11"></a> ### Licencia<a id="orgheadline11"></a>

View File

@ -14,7 +14,7 @@
Clone the repository: Clone the repository:
#+BEGIN_SRC sh #+BEGIN_SRC sh
$ git clone git://daemons.cf/jabbergram $ git clone https://git.daemons.it/drymer/jabbergram
$ cd jabbergram $ cd jabbergram
$ su -c "pip3 install -r requirements.txt" $ su -c "pip3 install -r requirements.txt"
$ su -c "python3 setup.py install" $ su -c "python3 setup.py install"
@ -93,9 +93,9 @@
Clonar el repositorio: Clonar el repositorio:
#+BEGIN_SRC sh #+BEGIN_SRC sh
$ git clone git://daemons.cf/jabbergram $ git clone https://git.daemons.it/drymer/jabbergram
$ cd jabbergram $ cd jabbergram
$ su -c "pip3 instalar -r requirements.txt" $ su -c "pip3 install -r requirements.txt"
$ su -c "python3 setup.py install" $ su -c "python3 setup.py install"
#+END_SRC #+END_SRC
*** Configuración *** Configuración
@ -111,7 +111,7 @@
# Ahora hay que pulsar desactivar # Ahora hay que pulsar desactivar
#+END_SRC #+END_SRC
La opción =/setprivacy= es para hacer que el robot pueda leer todo lo que se dice en el grupo, no sólo cuando se utilizan los comandos. Es necesario para hacer que =jabbergram= funcione. Más información sobre la creación los bots de =Telegrama= en su [[https://core.telegram.org/bots][página web]]. La opción =/setprivacy= es para hacer que el robot pueda leer todo lo que se dice en el grupo, no sólo cuando se utilizan los comandos. Es necesario para hacer que =jabbergram= funcione. Más información sobre la creación los bots de =Telegram= en su [[https://core.telegram.org/bots][página web]].
A continuación, hay que crear un archivo de configuración, que llamaremos =config.ini=. En ese archivo, introduce los siguientes parámetros: A continuación, hay que crear un archivo de configuración, que llamaremos =config.ini=. En ese archivo, introduce los siguientes parámetros:
@ -141,7 +141,7 @@
group = -10293943920 120301203 group = -10293943920 120301203
#+END_SRC #+END_SRC
De este modo, el muc "exampleMuc@muc.nope.org" se sincronizará con el grupo "-10293943920", y "segunda@muc.sip.org" con "120301203". De este modo, el muc "exampleMuc@muc.nope.org" se sincronizará con el grupo "-10293943920", y "segunda@muc.sip.org" con "120301203". Hecho esto, solo queda ejecutarlo en la terminal: =python3 jabbergram.py config.ini=. Hay que tenerla activa siempre que se quiera que funcione, obviamente.
*** Licencia *** Licencia
#+BEGIN_SRC text #+BEGIN_SRC text
This program is free software: you can redistribute it and / or modify This program is free software: you can redistribute it and / or modify

View File

@ -31,7 +31,7 @@ Clone the repository:
.. code-block:: sh .. code-block:: sh
:number-lines: 0 :number-lines: 0
$ git clone git://daemons.cf/jabbergram $ git clone https://git.daemons.it/drymer/jabbergram
$ cd jabbergram $ cd jabbergram
$ su -c "pip3 install -r requirements.txt" $ su -c "pip3 install -r requirements.txt"
$ su -c "python3 setup.py install" $ su -c "python3 setup.py install"
@ -135,7 +135,7 @@ Clonar el repositorio:
.. code-block:: sh .. code-block:: sh
:number-lines: 0 :number-lines: 0
$ git clone git://daemons.cf/jabbergram $ git clone https://git.daemons.it/drymer/jabbergram
$ cd jabbergram $ cd jabbergram
$ su -c "pip3 instalar -r requirements.txt" $ su -c "pip3 instalar -r requirements.txt"
$ su -c "python3 setup.py install" $ su -c "python3 setup.py install"

View File

@ -1,33 +1,42 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import configparser
import logging
from sys import argv
from threading import Thread
from time import sleep
from xml.dom import minidom
import sleekxmpp
import telegram
from sleekxmpp.xmlstream.stanzabase import ElementBase
from telegram.error import NetworkError, Unauthorized
try: try:
import requests import requests
except: except:
print("HTTP Upload support disabled.") logging.error("HTTP Upload support disabled.")
import sleekxmpp
import telegram
import configparser
from threading import Thread
from queue import Queue
from telegram.error import NetworkError, Unauthorized
from time import sleep
from sys import argv
from sys import exit
from sleekxmpp.xmlstream.stanzabase import ElementBase
from sleekxmpp.stanza.iq import Iq
from xml.dom import minidom
class Request(ElementBase): class Request(ElementBase):
"""Special class to create http_upload requests."""
namespace = 'urn:xmpp:http:upload' namespace = 'urn:xmpp:http:upload'
name = 'request' name = 'request'
plugin_attrib = 'request' plugin_attrib = 'request'
interfaces = set(('filename', 'size')) interfaces = set(('filename', 'size'))
sub_interfaces = interfaces sub_interfaces = interfaces
class Jabbergram(sleekxmpp.ClientXMPP): class Jabbergram(sleekxmpp.ClientXMPP):
def __init__(self, jid, password, rooms, nick, token, groups): """Main object."""
def __init__(self, jid, password, rooms, nick, token, groups, verify_ssl):
"""
Executed when the class is initialized. It adds session handlers, muc
handlers and send the telegram reading function and the HTTP upload
initializing functions to their respective threads.
"""
# XMPP # XMPP
super(Jabbergram, self).__init__(jid, password) super(Jabbergram, self).__init__(jid, password)
self.add_event_handler('session_start', self.start) self.add_event_handler('session_start', self.start)
@ -38,6 +47,7 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.token = token self.token = token
self.xmpp_users = {} self.xmpp_users = {}
self.jid = jid self.jid = jid
self.verify_ssl = verify_ssl
for muc in self.muc_rooms: for muc in self.muc_rooms:
self.add_event_handler("muc::%s::got_online" % muc, self.add_event_handler("muc::%s::got_online" % muc,
@ -49,7 +59,6 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.groups = groups.split() self.groups = groups.split()
self.bot = telegram.Bot(self.token) self.bot = telegram.Bot(self.token)
self.telegram_users = {} self.telegram_users = {}
self.group_name = {}
# initialize http upload on a thread since its needed to be connected # initialize http upload on a thread since its needed to be connected
# to xmpp # to xmpp
@ -66,6 +75,11 @@ class Jabbergram(sleekxmpp.ClientXMPP):
'connected') 'connected')
def init_http(self): def init_http(self):
"""
Initializes HTTP upload support. Sends a discovery stanza to the server
to find the HTTP upload component and asks for the max size a file can
be.
"""
self.http_upload = self.HttpUpload(self) self.http_upload = self.HttpUpload(self)
self.component = self.http_upload.discovery() self.component = self.http_upload.discovery()
@ -85,8 +99,8 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.max_size = None self.max_size = None
def read_tg(self): def read_tg(self):
"""Main telegram function."""
update_id = 0 update_id = 0
name = ''
# wait until http_upload has been tested # wait until http_upload has been tested
sleep(5) sleep(5)
@ -94,12 +108,29 @@ class Jabbergram(sleekxmpp.ClientXMPP):
try: try:
for update in self.bot.getUpdates(offset=update_id, for update in self.bot.getUpdates(offset=update_id,
timeout=10): timeout=10):
if not self.group_name: name = ''
self.group_name = update.message.chat.username size = 0
if update.edited_message:
update_id = update.update_id + 1
continue
if update.message.from_user:
user = update.message.from_user.username
# sometimes there's no user. weird, but it happens
if not user:
user = update.message.from_user.first_name
# sometimes there's no user. weird, but it happens
elif update.message['from']:
user = str(update.message['from'].first_name)
if update.message.audio or update.message.document or \ if update.message.audio or update.message.document or \
update.message.photo or update.message.video \ update.message.photo or update.message.video \
or update.message.voice or update.message.sticker: or update.message.voice or update.message.sticker:
# proceed only if http upload is available # proceed only if http upload is available
if self.max_size is not None: if self.max_size is not None:
if update.message.audio: if update.message.audio:
d_file = update.message.audio d_file = update.message.audio
@ -121,13 +152,18 @@ class Jabbergram(sleekxmpp.ClientXMPP):
d_file = update.message.voice d_file = update.message.voice
ext = '.ogg' ext = '.ogg'
size = d_file.file_size size = d_file.file_size
if self.max_size >= size: elif update.message.sticker:
d_file = update.message.sticker
ext = '.png'
size = d_file.file_size
if self.max_size >= int(size):
t_file = self.bot.getFile(d_file.file_id) t_file = self.bot.getFile(d_file.file_id)
f_name = '/tmp/' + d_file.file_id + ext f_name = '/tmp/' + d_file.file_id + ext
t_file.download(f_name) t_file.download(f_name)
url = self.http_upload.upload( url = self.http_upload.upload(
self.component, self.component,
'', f_name, size) self.verify_ssl,
f_name, size)
if update.message.caption: if update.message.caption:
message = update.message.caption + ' ' message = update.message.caption + ' '
@ -139,11 +175,11 @@ class Jabbergram(sleekxmpp.ClientXMPP):
message = 'A file has been uploaded to Telegr'\ message = 'A file has been uploaded to Telegr'\
'am, but is too big.' 'am, but is too big.'
else: else:
message = 'A file has been uploaderd to Telegram,'\ message = 'A file has been uploaded to Telegram,'\
'but the XMPP server doesn\'t support H'\ 'but the XMPP server doesn\'t support H'\
'TTP Upload.' 'TTP Upload.'
elif update.message.new_chat_member: elif update.message.new_chat_members:
message = 'This user has joined the group.' message = 'This user has joined the group.'
elif update.message.left_chat_member: elif update.message.left_chat_member:
message = 'This user has left the group.' message = 'This user has left the group.'
@ -161,28 +197,21 @@ class Jabbergram(sleekxmpp.ClientXMPP):
update.message.reply_to_message.text update.message.reply_to_message.text
else: else:
message = update.message.reply_to_message.text message = update.message.reply_to_message.text
message = message + ' <- ' + update.message.text
else: else:
message = update.message.text message = update.message.text
user = str(update.message.from_user.username)
# sometimes there's no user. weird, but it happens
if not user:
user = str(update.message.from_user.first_name)
# even weirder is that username or first_name exists
# let's take last_name
if not user:
user = str(update.message.from_user.last_name)
# Don't add name first if it's a reply
if name: if name:
msg = message msg = message + ' <- ' + user + ": " + \
update.message.text
else: else:
msg = user + ": " + message msg = user + ": " + message
if update.message.chat.type == 'supergroup' and \
update.message.chat.username:
chat = '@' + update.message.chat.username chat = '@' + update.message.chat.username
else:
chat = str(update.message.chat.id)
if chat not in self.groups: if chat not in self.groups:
chat = str(update.message.chat_id) chat = str(update.message.chat_id)
@ -194,15 +223,14 @@ class Jabbergram(sleekxmpp.ClientXMPP):
if user not in self.telegram_users[chat]: if user not in self.telegram_users[chat]:
self.telegram_users[chat] += ' ' + user self.telegram_users[chat] += ' ' + user
else: else:
self.telegram_users[chat] = ' ' + user self.telegram_users[chat] = ' ' + user
if message == '.users': if message == '.users':
self.say_users('telegram', muc, chat) self.say_users('telegram', receiver, chat)
elif message == '.help': elif message == '.help':
self.say_help('telegram', muc, chat) self.say_help('telegram', receiver, chat)
elif message == '.where': elif message == '.where':
self.say_where('telegram', muc, chat) self.say_where('telegram', receiver, chat)
else: else:
self.send_message(mto=receiver, mbody=msg, self.send_message(mto=receiver, mbody=msg,
mtype='groupchat') mtype='groupchat')
@ -212,7 +240,7 @@ class Jabbergram(sleekxmpp.ClientXMPP):
print(e) print(e)
sleep(1) sleep(1)
except Unauthorized: except Unauthorized as e:
print(e) print(e)
sleep(1) sleep(1)
@ -221,6 +249,7 @@ class Jabbergram(sleekxmpp.ClientXMPP):
print(e) print(e)
def start(self, event): def start(self, event):
"""Does some initial setup for XMPP and joins all mucs."""
self.get_roster() self.get_roster()
self.send_presence() self.send_presence()
@ -228,6 +257,7 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.plugin['xep_0045'].joinMUC(muc, self.nick, wait=True) self.plugin['xep_0045'].joinMUC(muc, self.nick, wait=True)
def muc_message(self, msg): def muc_message(self, msg):
"""Muc message's handler."""
muc_room = str(msg['from']).split('/')[0] muc_room = str(msg['from']).split('/')[0]
index = self.muc_rooms.index(muc_room) index = self.muc_rooms.index(muc_room)
tg_group = self.groups[index] tg_group = self.groups[index]
@ -243,6 +273,7 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.bot.sendMessage(tg_group, text=message) self.bot.sendMessage(tg_group, text=message)
def muc_online(self, presence): def muc_online(self, presence):
"""Muc presence's handler."""
user = presence['muc']['nick'] user = presence['muc']['nick']
muc = presence['from'].bare muc = presence['from'].bare
@ -253,6 +284,7 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.xmpp_users[muc] = [presence['muc']['nick']] self.xmpp_users[muc] = [presence['muc']['nick']]
def muc_offline(self, presence): def muc_offline(self, presence):
"""Muc presence's handler."""
user = presence['muc']['nick'] user = presence['muc']['nick']
muc = presence['from'].bare muc = presence['from'].bare
@ -260,6 +292,7 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.xmpp_users[muc].remove(presence['muc']['nick']) self.xmpp_users[muc].remove(presence['muc']['nick'])
def say_users(self, service, muc, group): def say_users(self, service, muc, group):
"""It returns the users on XMPP or Telegram."""
if service == 'xmpp': if service == 'xmpp':
if group in self.telegram_users: if group in self.telegram_users:
tg_users = self.telegram_users[group] tg_users = self.telegram_users[group]
@ -282,6 +315,7 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.bot.sendMessage(group, text=msg) self.bot.sendMessage(group, text=msg)
def say_help(self, service, muc, group): def say_help(self, service, muc, group):
"""Help command."""
msg = 'Hi, I\'m ' + self.bot.username + '. I have two commands : ".us'\ msg = 'Hi, I\'m ' + self.bot.username + '. I have two commands : ".us'\
'ers" and ".where".' 'ers" and ".where".'
if service == 'xmpp': if service == 'xmpp':
@ -290,9 +324,10 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.bot.sendMessage(group, text=msg) self.bot.sendMessage(group, text=msg)
def say_where(self, service, muc, group): def say_where(self, service, muc, group):
"""Returns Telegram's group location if it's public."""
if service == 'xmpp': if service == 'xmpp':
if self.group_name: if '@' in group:
msg = 'I\'m on http://telegram.me/' + self.group_name + '.' msg = 'I\'m on http://telegram.me/' + group.split('@')[1] + '.'
else: else:
msg = 'Sorry, I\'m on a private group, you\'ll have to ask fo'\ msg = 'Sorry, I\'m on a private group, you\'ll have to ask fo'\
'r an invitation.' 'r an invitation.'
@ -302,11 +337,13 @@ class Jabbergram(sleekxmpp.ClientXMPP):
self.bot.sendMessage(group, text=msg) self.bot.sendMessage(group, text=msg)
class HttpUpload(): class HttpUpload():
"""HTTP upload main class."""
def __init__(self, parent_self): def __init__(self, parent_self):
"""Init... Yep."""
self.parent_self = parent_self self.parent_self = parent_self
def discovery(self): def discovery(self):
"""Discovers all server's components."""
disco = sleekxmpp.basexmpp.BaseXMPP.Iq(self.parent_self) disco = sleekxmpp.basexmpp.BaseXMPP.Iq(self.parent_self)
disco['query'] = "http://jabber.org/protocol/disco#items" disco['query'] = "http://jabber.org/protocol/disco#items"
disco['type'] = 'get' disco['type'] = 'get'
@ -330,17 +367,18 @@ class Jabbergram(sleekxmpp.ClientXMPP):
return http_upload_component return http_upload_component
def disco_info(self, component): def disco_info(self, component):
"""Discovers HTTP upload components attributes."""
info = sleekxmpp.basexmpp.BaseXMPP.Iq(self.parent_self) info = sleekxmpp.basexmpp.BaseXMPP.Iq(self.parent_self)
info['query'] = "http://jabber.org/protocol/disco#info" info['query'] = "http://jabber.org/protocol/disco#info"
info['type'] = 'get' info['type'] = 'get'
info['from'] = self.parent_self.jid info['from'] = self.parent_self.jid
info['to'] = component info['to'] = component
response = str(info.send(timeout=30))
return str(info.send(timeout=30)) return response
def upload(self, component, verify_ssl, u_file, size): def upload(self, component, verify_ssl, u_file, size):
"""Uploads to HTTP upload."""
peticion = Request() peticion = Request()
peticion['filename'] = u_file.split('/')[-1] peticion['filename'] = u_file.split('/')[-1]
peticion['size'] = str(size) peticion['size'] = str(size)
@ -356,7 +394,7 @@ class Jabbergram(sleekxmpp.ClientXMPP):
xml = minidom.parseString(str(send)) xml = minidom.parseString(str(send))
put_url = xml.getElementsByTagName('put')[0].firstChild.data put_url = xml.getElementsByTagName('put')[0].firstChild.data
if verify_ssl == '' or verif_ssl == 'False': if verify_ssl == 'False':
req = requests.put(put_url, data=open(u_file, 'rb'), req = requests.put(put_url, data=open(u_file, 'rb'),
verify=False) verify=False)
else: else:
@ -386,8 +424,10 @@ if __name__ == '__main__':
nick = config[3] nick = config[3]
token = config[4] token = config[4]
groups = config[5] groups = config[5]
verify_ssl = config[6]
xmpp = Jabbergram(jid, password, muc_rooms, nick, token, groups) xmpp = Jabbergram(jid, password, muc_rooms, nick, token, groups,
verify_ssl)
xmpp.register_plugin('xep_0045') xmpp.register_plugin('xep_0045')
if xmpp.connect(): if xmpp.connect():

View File

@ -1,3 +1,3 @@
sleekxmpp >= 1.3.1 sleekxmpp >= 1.3.2
python-telegram-bot >= 4.0.3 python-telegram-bot >= 6.1.0
requests >= 2.11.1 requests >= 2.11.1

View File

@ -30,6 +30,9 @@ printed = []
while True: while True:
try: try:
for update in bot.getUpdates(offset=update_id, timeout=10): for update in bot.getUpdates(offset=update_id, timeout=10):
if update.edited_message:
update_id = update.update_id + 1
continue
chat_id = update.message.chat_id chat_id = update.message.chat_id
chat_title = update.message chat_title = update.message
if chat_id not in printed: if chat_id not in printed:

View File

@ -10,8 +10,8 @@ setup(name='jabbergram',
long_description=open('README.rst', encoding='utf-8').read(), long_description=open('README.rst', encoding='utf-8').read(),
author='drymer', author='drymer',
author_email='drymer@autistici.org', author_email='drymer@autistici.org',
url='http://daemons.cf/cgit/jabbergram/about/', url='http://git.daemons.it/drymer/jabbergram/about/',
download_url='http://daemons.cf/cgit/jabbergram/snapshot/jabbergram-' + VERSION + '.tar.gz', download_url='https://git.daemons.it/drymer/jabbergram/archive/' + VERSION + '.tar.gz',
scripts=['jabbergram.py'], scripts=['jabbergram.py'],
license="GPLv3", license="GPLv3",
install_requires=[ install_requires=[