Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

19 changed files with 296 additions and 1009 deletions

View file

@ -20,15 +20,14 @@ Slixfeed is primarily designed for XMPP (aka Jabber), yet it is built to be exte
## Features ## Features
- **Visual interface** - Interactive interface for XMPP using Ad-Hoc Commands,
- **Ease** - Slixfeed automatically scans (i.e. crawls) for syndication feeds of given URL. - **Ease** - Slixfeed automatically scans (i.e. crawls) for syndication feeds of given URL.
- **Encryption** - Messages are encrypted with the OMEMO standard.
- **Export** - Download articles as ePUB, HTML, Markdown and PDF. - **Export** - Download articles as ePUB, HTML, Markdown and PDF.
- **Filtering** - Filter news items using lists of allow and deny. - **Filtering** - Filter news items using lists of allow and deny.
- **Multimedia** - Display audios pictures and videos inline. - **Multimedia** - Display audios pictures and videos inline.
- **Privacy** - Redirect to alternative back-ends, such as Invidious, Librarian, Nitter, for increased privacy, productivity and security. - **Privacy** - Redirect to alternative back-ends, such as Invidious, Librarian, Nitter, for increased privacy, productivity and security.
- **Portable** - Export and import feeds with a standard OPML file. - **Portable** - Export and import feeds with a standard OPML file.
- **Simultaneous** - Slixfeed is designed to handle multiple contacts, including groupchats, Simultaneously. - **Simultaneous** - Slixfeed is designed to handle multiple contacts, including groupchats, Simultaneously.
- **Visual interface** - Interactive interface for XMPP using Ad-Hoc Commands,
## Preview ## Preview
@ -57,7 +56,7 @@ It is possible to install Slixfeed using pip and pipx.
``` ```
$ python3 -m venv .venv $ python3 -m venv .venv
$ source .venv/bin/activate $ source .venv/bin/activate
$ pip install git+https://git.xmpp-it.net/sch/Slixfeed $ pip install git+https://gitgud.io/sjehuda/slixfeed
``` ```
#### pipx #### pipx
@ -65,14 +64,14 @@ $ pip install git+https://git.xmpp-it.net/sch/Slixfeed
##### Install ##### Install
``` ```
$ pipx install git+https://git.xmpp-it.net/sch/Slixfeed $ pipx install git+https://gitgud.io/sjehuda/slixfeed
``` ```
##### Update ##### Update
``` ```
$ pipx uninstall slixfeed $ pipx uninstall slixfeed
$ pipx install git+https://git.xmpp-it.net/sch/Slixfeed $ pipx install git+https://gitgud.io/sjehuda/slixfeed
``` ```
### Start ### Start

View file

@ -39,22 +39,16 @@ keywords = [
] ]
# urls = {Homepage = "https://gitgud.io/sjehuda/slixfeed"} # urls = {Homepage = "https://gitgud.io/sjehuda/slixfeed"}
dependencies = [ dependencies = [
"aiofiles",
"aiohttp", "aiohttp",
# "daemonize", # "daemonize",
"feedparser", "feedparser",
"lxml", "lxml",
"omemo", # OMEMO
# "pysocks", # "pysocks",
"protobuf==3.20.3", # OMEMO
"python-dateutil", "python-dateutil",
"requests", "requests",
"slixmpp", "slixmpp",
"slixmpp-omemo", # OMEMO
"tomli", # Python 3.10 "tomli", # Python 3.10
"tomli_w", "tomli_w",
"X3DH", # OMEMO
"XEdDSA", # OMEMO
] ]
[project.urls] [project.urls]

View file

@ -11,7 +11,6 @@ interval = 300 # Update interval (Minimum value 10)
length = 300 # Maximum length of summary (Value 0 to disable) length = 300 # Maximum length of summary (Value 0 to disable)
media = 0 # Display media (audio, image, video) when available media = 0 # Display media (audio, image, video) when available
old = 0 # Mark entries of newly added entries as unread old = 0 # Mark entries of newly added entries as unread
omemo = 1 # Encrypt messages with OMEMO
quantum = 3 # Amount of entries per update quantum = 3 # Amount of entries per update
random = 0 # Pick random item from database random = 0 # Pick random item from database

View file

@ -51,31 +51,27 @@ logger = Logger(__name__)
# setting_jid.setting_key has value, otherwise resort to setting_default.setting_key. # setting_jid.setting_key has value, otherwise resort to setting_default.setting_key.
class Config: class Config:
def add_settings_default(self): def add_settings_default(settings):
settings_default = get_values('settings.toml', 'settings') settings_default = get_values('settings.toml', 'settings')
self.defaults = settings_default settings['default'] = settings_default
# TODO Open SQLite file once # TODO Open SQLite file once
def add_settings_jid(self, jid_bare, db_file): def add_settings_jid(settings, jid_bare, db_file):
self.settings[jid_bare] = {} settings[jid_bare] = {}
for key in self.defaults['default']: for key in ('archive', 'enabled', 'filter', 'formatting', 'interval',
'length', 'media', 'old', 'quantum'):
value = sqlite.get_setting_value(db_file, key) value = sqlite.get_setting_value(db_file, key)
if value: if value: settings[jid_bare][key] = value[0]
self.settings[jid_bare][key] = value[0]
elif key not in ('check', 'formatting'):
# NOTE This might neglects the need for
# self.defaults of get_setting_value
self.settings[jid_bare][key] = self.defaults['default'][key]
def get_settings_xmpp(key=None): def get_settings_xmpp(key=None):
result = get_values('accounts.toml', 'xmpp') result = get_values('accounts.toml', 'xmpp')
result = result[key] if key else result result = result[key] if key else result
return result return result
async def set_setting_value(self, jid_bare, db_file, key, val): async def set_setting_value(settings, jid_bare, db_file, key, val):
key = key.lower() key = key.lower()
key_val = [key, val] key_val = [key, val]
self.settings[jid_bare][key] = val settings[jid_bare][key] = val
if sqlite.is_setting_key(db_file, key): if sqlite.is_setting_key(db_file, key):
await sqlite.update_setting_value(db_file, key_val) await sqlite.update_setting_value(db_file, key_val)
else: else:
@ -83,11 +79,11 @@ class Config:
# TODO Segregate Jabber ID settings from Slixfeed wide settings. # TODO Segregate Jabber ID settings from Slixfeed wide settings.
# self.settings, self.settings_xmpp, self.settings_irc etc. # self.settings, self.settings_xmpp, self.settings_irc etc.
def get_setting_value(self, jid_bare, key): def get_setting_value(settings, jid_bare, key):
if jid_bare in self.settings and key in self.settings[jid_bare]: if jid_bare in settings and key in settings[jid_bare]:
value = self.settings[jid_bare][key] value = settings[jid_bare][key]
else: else:
value = self.defaults['default'][key] value = settings['default'][key]
return value return value
class ConfigNetwork: class ConfigNetwork:
@ -109,71 +105,6 @@ class ConfigJabberID:
settings[jid_bare][key] = value settings[jid_bare][key] = value
class Data:
def get_default_data_directory():
"""
Determine the directory path where dbfile will be stored.
* If $XDG_DATA_HOME is defined, use it;
* else if $HOME exists, use it;
* else if the platform is Windows, use %APPDATA%;
* else use the current directory.
Returns
-------
str
Path to database file.
Note
----
This function was taken from project buku.
See https://github.com/jarun/buku
* Arun Prakash Jana (jarun)
* Dmitry Marakasov (AMDmi3)
"""
# data_home = xdg.BaseDirectory.xdg_data_home
data_home = os.environ.get('XDG_DATA_HOME')
if data_home is None:
if os.environ.get('HOME') is None:
if sys.platform == 'win32':
data_home = os.environ.get('APPDATA')
if data_home is None:
return os.path.abspath('.slixfeed/data')
else:
return os.path.abspath('.slixfeed/data')
else:
data_home = os.path.join(
os.environ.get('HOME'), '.local', 'share'
)
return os.path.join(data_home, 'slixfeed')
def get_pathname_to_omemo_directory():
"""
Get OMEMO directory.
Parameters
----------
None
Returns
-------
object
Coroutine object.
"""
db_dir = get_default_data_directory()
if not os.path.isdir(db_dir):
os.mkdir(db_dir)
if not os.path.isdir(db_dir + "/omemo"):
os.mkdir(db_dir + "/omemo")
omemo_dir = os.path.join(db_dir, "omemo")
return omemo_dir
def get_values(filename, key=None): def get_values(filename, key=None):
config_dir = get_default_config_directory() config_dir = get_default_config_directory()
if not os.path.isdir(config_dir): if not os.path.isdir(config_dir):

View file

@ -36,7 +36,6 @@ NOTE
""" """
import aiofiles
from aiohttp import ClientError, ClientSession, ClientTimeout from aiohttp import ClientError, ClientSession, ClientTimeout
from asyncio import TimeoutError from asyncio import TimeoutError
# from asyncio.exceptions import IncompleteReadError # from asyncio.exceptions import IncompleteReadError
@ -46,8 +45,6 @@ from asyncio import TimeoutError
import requests import requests
import slixfeed.config as config import slixfeed.config as config
from slixfeed.log import Logger from slixfeed.log import Logger
# import urllib.request
# from urllib.error import HTTPError
logger = Logger(__name__) logger = Logger(__name__)
@ -58,6 +55,7 @@ except:
"Package magnet2torrent was not found.\n" "Package magnet2torrent was not found.\n"
"BitTorrent is disabled.") "BitTorrent is disabled.")
# class Dat: # class Dat:
# async def dat(): # async def dat():
@ -70,154 +68,52 @@ except:
# class Gopher: # class Gopher:
# async def gopher(): # async def gopher():
# class Http:
# async def http():
# class Ipfs: # class Ipfs:
# async def ipfs(): # async def ipfs():
class Http: def http_response(url):
"""
Download response headers.
Parameters
----------
url : str
URL.
# def fetch_media(url, pathname): Returns
# try: -------
# urllib.request.urlretrieve(url, pathname) response: requests.models.Response
# status = 1 HTTP Header Response.
# except HTTPError as e:
# logger.error(e)
# status = 0
# return status
Result would contain these:
async def fetch_headers(url): response.encoding
network_settings = config.get_values('settings.toml', 'network') response.headers
user_agent = (network_settings['user_agent'] or 'Slixfeed/0.1') response.history
headers = {'User-Agent': user_agent} response.reason
proxy = (network_settings['http_proxy'] or None) response.status_code
timeout = ClientTimeout(total=10) response.url
async with ClientSession(headers=headers) as session: """
async with session.get(url, proxy=proxy, user_agent = (
# proxy_auth=(proxy_username, proxy_password), config.get_value(
timeout=timeout "settings", "Network", "user_agent")
) as response: ) or 'Slixfeed/0.1'
headers = response.headers headers = {
return headers "User-Agent": user_agent
# print("Headers for URL:", url) }
# for header_name, header_value in headers.items(): try:
# print(f"{header_name}: {header_value}") # Do not use HEAD request because it appears that too many sites would
# deny it.
# response = requests.head(url, headers=headers, allow_redirects=True)
# TODO Write file to disk. Consider aiofiles response = requests.get(url, headers=headers, allow_redirects=True)
async def fetch_media(url, pathname): except Exception as e:
""" logger.warning('Error in HTTP response')
Download media content of given URL. logger.error(e)
response = None
Parameters return response
----------
url : str
URL.
pathname : list
Pathname (including filename) to save content to.
Returns
-------
msg: list or str
Document or error message.
"""
network_settings = config.get_values('settings.toml', 'network')
user_agent = (network_settings['user_agent'] or 'Slixfeed/0.1')
headers = {'User-Agent': user_agent}
proxy = (network_settings['http_proxy'] or None)
timeout = ClientTimeout(total=10)
async with ClientSession(headers=headers) as session:
# async with ClientSession(trust_env=True) as session:
try:
async with session.get(url, proxy=proxy,
# proxy_auth=(proxy_username, proxy_password),
timeout=timeout
) as response:
status = response.status
if status in (200, 201):
f = await aiofiles.open(pathname, mode='wb')
await f.write(await response.read())
await f.close()
try:
result = {'charset': response.charset,
'content_length': response.content_length,
'content_type': response.content_type,
'error': False,
'message': None,
'original_url': url,
'status_code': status,
'response_url': response.url}
except:
result = {'error': True,
'message': 'Could not get document.',
'original_url': url,
'status_code': status,
'response_url': response.url}
else:
result = {'error': True,
'message': 'HTTP Error:' + str(status),
'original_url': url,
'status_code': status,
'response_url': response.url}
except ClientError as e:
result = {'error': True,
'message': 'Error:' + str(e) if e else 'ClientError',
'original_url': url,
'status_code': None}
except TimeoutError as e:
result = {'error': True,
'message': 'Timeout:' + str(e) if e else 'TimeoutError',
'original_url': url,
'status_code': None}
except Exception as e:
logger.error(e)
result = {'error': True,
'message': 'Error:' + str(e) if e else 'Error',
'original_url': url,
'status_code': None}
return result
def http_response(url):
"""
Download response headers.
Parameters
----------
url : str
URL.
Returns
-------
response: requests.models.Response
HTTP Header Response.
Result would contain these:
response.encoding
response.headers
response.history
response.reason
response.status_code
response.url
"""
user_agent = (
config.get_value(
"settings", "Network", "user_agent")
) or 'Slixfeed/0.1'
headers = {
"User-Agent": user_agent
}
try:
# Do not use HEAD request because it appears that too many sites would
# deny it.
# response = requests.head(url, headers=headers, allow_redirects=True)
response = requests.get(url, headers=headers, allow_redirects=True)
except Exception as e:
logger.warning('Error in HTTP response')
logger.error(e)
response = None
return response
async def http(url): async def http(url):

View file

@ -2762,39 +2762,6 @@ def get_active_feeds_url(db_file):
return result return result
def get_active_feeds_url_sorted_by_last_scanned(db_file):
"""
Query table feeds for active URLs and sort them by last scanned time.
Parameters
----------
db_file : str
Path to database file.
Returns
-------
result : tuple
URLs of active feeds.
"""
function_name = sys._getframe().f_code.co_name
logger.debug('{}: db_file: {}'
.format(function_name, db_file))
with create_connection(db_file) as conn:
cur = conn.cursor()
sql = (
"""
SELECT feeds_properties.url
FROM feeds_properties
INNER JOIN feeds_preferences ON feeds_properties.id = feeds_preferences.feed_id
INNER JOIN feeds_state ON feeds_properties.id = feeds_state.feed_id
WHERE feeds_preferences.enabled = 1
ORDER BY feeds_state.scanned
"""
)
result = cur.execute(sql).fetchall()
return result
def get_tags(db_file): def get_tags(db_file):
""" """
Query table tags and list items. Query table tags and list items.

View file

@ -348,7 +348,7 @@ class Feed:
if new_entries: if new_entries:
await sqlite.add_entries_and_update_feed_state( await sqlite.add_entries_and_update_feed_state(
db_file, feed_id, new_entries) db_file, feed_id, new_entries)
old = Config.get_setting_value(self, jid_bare, 'old') old = Config.get_setting_value(self.settings, jid_bare, 'old')
if not old: await sqlite.mark_feed_as_read(db_file, feed_id) if not old: await sqlite.mark_feed_as_read(db_file, feed_id)
result_final = {'link' : url, result_final = {'link' : url,
'index' : feed_id, 'index' : feed_id,
@ -1276,7 +1276,7 @@ class FeedTask:
logger.info('Scanning for updates for JID {}'.format(jid_bare)) logger.info('Scanning for updates for JID {}'.format(jid_bare))
while True: while True:
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
urls = sqlite.get_active_feeds_url_sorted_by_last_scanned(db_file) urls = sqlite.get_active_feeds_url(db_file)
for url in urls: for url in urls:
Message.printer('Scanning updates for URL {} ...'.format(url)) Message.printer('Scanning updates for URL {} ...'.format(url))
url = url[0] url = url[0]
@ -1335,7 +1335,7 @@ class FeedTask:
new_entries.extend([new_entry]) new_entries.extend([new_entry])
if new_entries: if new_entries:
await sqlite.add_entries_and_update_feed_state(db_file, feed_id, new_entries) await sqlite.add_entries_and_update_feed_state(db_file, feed_id, new_entries)
limit = Config.get_setting_value(self, jid_bare, 'archive') limit = Config.get_setting_value(self.settings, jid_bare, 'archive')
ixs = sqlite.get_entries_id_of_feed(db_file, feed_id) ixs = sqlite.get_entries_id_of_feed(db_file, feed_id)
ixs_invalid = {} ixs_invalid = {}
for ix in ixs: for ix in ixs:
@ -1360,8 +1360,8 @@ class FeedTask:
# TODO return number of archived entries and add if statement to run archive maintainence function # TODO return number of archived entries and add if statement to run archive maintainence function
await sqlite.maintain_archive(db_file, limit) await sqlite.maintain_archive(db_file, limit)
# await sqlite.process_invalid_entries(db_file, ixs) # await sqlite.process_invalid_entries(db_file, ixs)
await asyncio.sleep(60 * 2) await asyncio.sleep(50)
val = Config.get_setting_value(self, jid_bare, 'check') val = Config.get_setting_value(self.settings, jid_bare, 'check')
await asyncio.sleep(60 * float(val)) await asyncio.sleep(60 * float(val))
# Schedule to call this function again in 90 minutes # Schedule to call this function again in 90 minutes
# loop.call_at( # loop.call_at(

View file

@ -67,107 +67,6 @@ except:
logger = Logger(__name__) logger = Logger(__name__)
class Config:
def get_default_data_directory():
if os.environ.get('HOME'):
data_home = os.path.join(os.environ.get('HOME'), '.local', 'share')
return os.path.join(data_home, 'kaikout')
elif sys.platform == 'win32':
data_home = os.environ.get('APPDATA')
if data_home is None:
return os.path.join(
os.path.dirname(__file__) + '/kaikout_data')
else:
return os.path.join(os.path.dirname(__file__) + '/kaikout_data')
def get_default_config_directory():
"""
Determine the directory path where configuration will be stored.
* If $XDG_CONFIG_HOME is defined, use it;
* else if $HOME exists, use it;
* else if the platform is Windows, use %APPDATA%;
* else use the current directory.
Returns
-------
str
Path to configuration directory.
"""
# config_home = xdg.BaseDirectory.xdg_config_home
config_home = os.environ.get('XDG_CONFIG_HOME')
if config_home is None:
if os.environ.get('HOME') is None:
if sys.platform == 'win32':
config_home = os.environ.get('APPDATA')
if config_home is None:
return os.path.abspath('.')
else:
return os.path.abspath('.')
else:
config_home = os.path.join(
os.environ.get('HOME'), '.config'
)
return os.path.join(config_home, 'kaikout')
def get_setting_value(db_file, key):
value = sqlite.get_setting_value(db_file, key)
if value:
value = value[0]
else:
value = Config.get_value('settings', 'Settings', key)
return value
def get_values(filename, key=None):
config_dir = Config.get_default_config_directory()
if not os.path.isdir(config_dir):
config_dir = '/usr/share/slixfeed/'
if not os.path.isdir(config_dir):
config_dir = os.path.dirname(__file__) + "/assets"
config_file = os.path.join(config_dir, filename)
with open(config_file, mode="rb") as defaults:
result = tomllib.load(defaults)
values = result[key] if key else result
return values
class Database:
def instantiate(jid_bare):
"""
Callback function to instantiate action on database.
Parameters
----------
jid_file : str
Filename.
callback : ?
Function name.
message : str, optional
Optional kwarg when a message is a part or
required argument. The default is None.
Returns
-------
object
Coroutine object.
"""
db_dir = Config.get_default_data_directory()
if not os.path.isdir(db_dir):
os.mkdir(db_dir)
if not os.path.isdir(db_dir + "/sqlite"):
os.mkdir(db_dir + "/sqlite")
db_file = os.path.join(db_dir, "sqlite", r"{}.db".format(jid_bare))
sqlite.create_tables(db_file)
return db_file
class DateAndTime: class DateAndTime:
#https://feedparser.readthedocs.io/en/latest/date-parsing.html #https://feedparser.readthedocs.io/en/latest/date-parsing.html
@ -327,7 +226,6 @@ class Html:
'//img[not(' '//img[not('
'contains(@src, "avatar") or ' 'contains(@src, "avatar") or '
'contains(@src, "cc-by-sa") or ' 'contains(@src, "cc-by-sa") or '
'contains(@src, "data:image/") or '
'contains(@src, "emoji") or ' 'contains(@src, "emoji") or '
'contains(@src, "icon") or ' 'contains(@src, "icon") or '
'contains(@src, "logo") or ' 'contains(@src, "logo") or '

View file

@ -1,2 +1,2 @@
__version__ = '0.1.92' __version__ = '0.1.85'
__version_info__ = (0, 1, 92) __version_info__ = (0, 1, 85)

View file

@ -24,29 +24,21 @@ TODO
""" """
import asyncio import asyncio
import os
from pathlib import Path
from random import randrange # pending_tasks: Use a list and read the first index (i.e. index 0). from random import randrange # pending_tasks: Use a list and read the first index (i.e. index 0).
import slixfeed.config as config import slixfeed.config as config
from slixfeed.config import Config from slixfeed.config import Config
import slixfeed.fetch as fetch
from slixfeed.fetch import Http
from slixfeed.log import Logger from slixfeed.log import Logger
import slixfeed.sqlite as sqlite import slixfeed.sqlite as sqlite
from slixfeed.syndication import FeedTask from slixfeed.syndication import FeedTask
from slixfeed.utilities import Documentation, Html, MD, Task, Url from slixfeed.utilities import Documentation, Html, MD, Task, Url
from slixfeed.xmpp.commands import XmppCommands from slixfeed.xmpp.commands import XmppCommands
from slixfeed.xmpp.encryption import XmppOmemo
from slixfeed.xmpp.message import XmppMessage from slixfeed.xmpp.message import XmppMessage
from slixfeed.xmpp.presence import XmppPresence from slixfeed.xmpp.presence import XmppPresence
from slixfeed.xmpp.status import XmppStatusTask from slixfeed.xmpp.status import XmppStatusTask
from slixfeed.xmpp.upload import XmppUpload from slixfeed.xmpp.upload import XmppUpload
from slixfeed.xmpp.utilities import XmppUtilities from slixfeed.xmpp.utilities import XmppUtilities
from slixmpp import JID
from slixmpp.stanza import Message
import sys import sys
import time import time
from typing import Optional
logger = Logger(__name__) logger = Logger(__name__)
@ -63,7 +55,7 @@ logger = Logger(__name__)
class XmppChat: class XmppChat:
async def process_message(self, message: Message, allow_untrusted: bool = False) -> None: async def process_message(self, message):
""" """
Process incoming message stanzas. Be aware that this also Process incoming message stanzas. Be aware that this also
includes MUC messages and error messages. It is usually includes MUC messages and error messages. It is usually
@ -77,27 +69,25 @@ class XmppChat:
for stanza objects and the Message stanza to see for stanza objects and the Message stanza to see
how it may be used. how it may be used.
""" """
message_from = message['from'] if message['type'] in ('chat', 'groupchat', 'normal'):
message_type = message['type'] jid_bare = message['from'].bare
if message_type in ('chat', 'groupchat', 'normal'):
jid_bare = message_from.bare
command = ' '.join(message['body'].split()) command = ' '.join(message['body'].split())
command_time_start = time.time() command_time_start = time.time()
# if (message_type == 'groupchat' and # if (message['type'] == 'groupchat' and
# message['muc']['nick'] == self.alias): # message['muc']['nick'] == self.alias):
# return # return
# FIXME Code repetition. See below. # FIXME Code repetition. See below.
# TODO Check alias by nickname associated with conference # TODO Check alias by nickname associated with conference
if message_type == 'groupchat': if message['type'] == 'groupchat':
if (message['muc']['nick'] == self.alias): if (message['muc']['nick'] == self.alias):
return return
jid_full = message_from.full jid_full = str(message['from'])
if not XmppUtilities.is_moderator(self, jid_bare, jid_full): if not XmppUtilities.is_moderator(self, jid_bare, jid_full):
return return
if message_type == 'groupchat': if message['type'] == 'groupchat':
# nick = message['from'][message['from'].index('/')+1:] # nick = message['from'][message['from'].index('/')+1:]
# nick = str(message['from']) # nick = str(message['from'])
# nick = nick[nick.index('/')+1:] # nick = nick[nick.index('/')+1:]
@ -119,7 +109,7 @@ class XmppChat:
# if nick not in operator: # if nick not in operator:
# return # return
# approved = False # approved = False
jid_full = message_from.full jid_full = str(message['from'])
if not XmppUtilities.is_moderator(self, jid_bare, jid_full): if not XmppUtilities.is_moderator(self, jid_bare, jid_full):
return return
# if role == 'moderator': # if role == 'moderator':
@ -150,27 +140,17 @@ class XmppChat:
# await compose.message(self, jid_bare, message) # await compose.message(self, jid_bare, message)
if self['xep_0384'].is_encrypted(message): if message['type'] == 'groupchat':
allow_untrusted=True # Temporary fix. This should be handled by "retry""
command, omemo_decrypted, retry = await XmppOmemo.decrypt(
self, message, allow_untrusted)
if retry:
command, omemo_decrypted, retry = await XmppOmemo.decrypt(
self, message, allow_untrusted=True)
else:
omemo_decrypted = None
if message_type == 'groupchat':
command = command[1:] command = command[1:]
command_lowercase = command.lower() command_lowercase = command.lower()
logger.debug([message_from.full, ':', command]) logger.debug([str(message['from']), ':', command])
# Support private message via groupchat # Support private message via groupchat
# See https://codeberg.org/poezio/slixmpp/issues/3506 # See https://codeberg.org/poezio/slixmpp/issues/3506
if message_type == 'chat' and message.get_plugin('muc', check=True): if message['type'] == 'chat' and message.get_plugin('muc', check=True):
# jid_bare = message_from.bare # jid_bare = message['from'].bare
jid_full = message_from.full jid_full = str(message['from'])
if (jid_bare == jid_full[:jid_full.index('/')]): if (jid_bare == jid_full[:jid_full.index('/')]):
# TODO Count and alert of MUC-PM attempts # TODO Count and alert of MUC-PM attempts
return return
@ -237,7 +217,7 @@ class XmppChat:
command = command[4:] command = command[4:]
url = command.split(' ')[0] url = command.split(' ')[0]
title = ' '.join(command.split(' ')[1:]) title = ' '.join(command.split(' ')[1:])
response = await XmppCommands.feed_add( response = XmppCommands.feed_add(
url, db_file, jid_bare, title) url, db_file, jid_bare, title)
case _ if command_lowercase.startswith('allow +'): case _ if command_lowercase.startswith('allow +'):
val = command[7:] val = command[7:]
@ -347,25 +327,15 @@ class XmppChat:
# self.pending_tasks[jid_bare][self.pending_tasks_counter] = status_message # self.pending_tasks[jid_bare][self.pending_tasks_counter] = status_message
XmppPresence.send(self, jid_bare, status_message, XmppPresence.send(self, jid_bare, status_message,
status_type=status_type) status_type=status_type)
pathname, response = XmppCommands.export_feeds( filename, response = XmppCommands.export_feeds(
jid_bare, ext) jid_bare, ext)
encrypt_omemo = Config.get_setting_value(self, jid_bare, 'omemo') url = await XmppUpload.start(self, jid_bare, filename)
encrypted = True if encrypt_omemo else False
url = await XmppUpload.start(self, jid_bare, Path(pathname), encrypted=encrypted)
# response = ( # response = (
# 'Feeds exported successfully to {}.\n{}' # 'Feeds exported successfully to {}.\n{}'
# ).format(ex, url) # ).format(ex, url)
# XmppMessage.send_oob_reply_message(message, url, response) # XmppMessage.send_oob_reply_message(message, url, response)
if url: chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
chat_type = await XmppUtilities.get_chat_type(self, jid_bare) XmppMessage.send_oob(self, jid_bare, url, chat_type)
if encrypted:
url_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, message_from, url)
XmppMessage.send_omemo_oob(self, message_from, url_encrypted, chat_type)
else:
XmppMessage.send_oob(self, jid_bare, url, chat_type)
else:
response = 'OPML file export has been failed.'
del self.pending_tasks[jid_bare][pending_tasks_num] del self.pending_tasks[jid_bare][pending_tasks_num]
# del self.pending_tasks[jid_bare][self.pending_tasks_counter] # del self.pending_tasks[jid_bare][self.pending_tasks_counter]
XmppStatusTask.restart_task(self, jid_bare) XmppStatusTask.restart_task(self, jid_bare)
@ -383,7 +353,7 @@ class XmppChat:
response = (first_line + result + response = (first_line + result +
'\n```\nTotal of {} feeds'.format(number)) '\n```\nTotal of {} feeds'.format(number))
case 'goodbye': case 'goodbye':
if message_type == 'groupchat': if message['type'] == 'groupchat':
await XmppCommands.muc_leave(self, jid_bare) await XmppCommands.muc_leave(self, jid_bare)
else: else:
response = 'This command is valid in groupchat only.' response = 'This command is valid in groupchat only.'
@ -408,18 +378,18 @@ class XmppChat:
# del self.pending_tasks[jid_bare][self.pending_tasks_counter] # del self.pending_tasks[jid_bare][self.pending_tasks_counter]
XmppStatusTask.restart_task(self, jid_bare) XmppStatusTask.restart_task(self, jid_bare)
case _ if command_lowercase.startswith('pubsub list'): case _ if command_lowercase.startswith('pubsub list'):
jid_full_pubsub = command[12:] jid = command[12:]
response = 'List of nodes for {}:\n```\n'.format(jid_full_pubsub) response = 'List of nodes for {}:\n```\n'.format(jid)
response = await XmppCommands.pubsub_list(self, jid_full_pubsub) response = await XmppCommands.pubsub_list(self, jid)
response += '```' response += '```'
case _ if command_lowercase.startswith('pubsub send'): case _ if command_lowercase.startswith('pubsub send'):
if XmppUtilities.is_operator(self, jid_bare): if XmppUtilities.is_operator(self, jid_bare):
info = command[12:] info = command[12:]
info = info.split(' ') info = info.split(' ')
jid_full_pubsub = info[0] jid = info[0]
# num = int(info[1]) # num = int(info[1])
if jid_full_pubsub: if jid:
response = XmppCommands.pubsub_send(self, info, jid_full_pubsub) response = XmppCommands.pubsub_send(self, info, jid)
else: else:
response = ('This action is restricted. ' response = ('This action is restricted. '
'Type: sending news to PubSub.') 'Type: sending news to PubSub.')
@ -483,13 +453,6 @@ class XmppChat:
self, jid_bare, db_file) self, jid_bare, db_file)
case _ if command_lowercase.startswith('next'): case _ if command_lowercase.startswith('next'):
num = command[5:] num = command[5:]
if num:
try:
int(num)
except:
# NOTE Show this text as a status message
# response = 'Argument for command "next" must be an integer.'
num = None
await XmppChatAction.send_unread_items(self, jid_bare, num) await XmppChatAction.send_unread_items(self, jid_bare, num)
XmppStatusTask.restart_task(self, jid_bare) XmppStatusTask.restart_task(self, jid_bare)
case _ if command_lowercase.startswith('node delete'): case _ if command_lowercase.startswith('node delete'):
@ -511,12 +474,6 @@ class XmppChat:
case 'old': case 'old':
response = await XmppCommands.set_old_on( response = await XmppCommands.set_old_on(
self, jid_bare, db_file) self, jid_bare, db_file)
case 'omemo off':
response = await XmppCommands.set_omemo_off(
self, jid_bare, db_file)
case 'omemo on':
response = await XmppCommands.set_omemo_on(
self, jid_bare, db_file)
case 'options': case 'options':
response = 'Options:\n```' response = 'Options:\n```'
response += XmppCommands.print_options(self, jid_bare) response += XmppCommands.print_options(self, jid_bare)
@ -595,9 +552,9 @@ class XmppChat:
XmppPresence.send(self, jid_bare, status_message, XmppPresence.send(self, jid_bare, status_message,
status_type=status_type) status_type=status_type)
await asyncio.sleep(5) await asyncio.sleep(5)
callbacks = (FeedTask, XmppChatTask, XmppStatusTask) tasks = (FeedTask, XmppChatTask, XmppStatusTask)
response = await XmppCommands.scheduler_start( response = await XmppCommands.scheduler_start(
self, db_file, jid_bare, callbacks) self, db_file, jid_bare, tasks)
case 'stats': case 'stats':
response = XmppCommands.print_statistics(db_file) response = XmppCommands.print_statistics(db_file)
case 'stop': case 'stop':
@ -624,20 +581,8 @@ class XmppChat:
command_time_finish = time.time() command_time_finish = time.time()
command_time_total = command_time_finish - command_time_start command_time_total = command_time_finish - command_time_start
command_time_total = round(command_time_total, 3) command_time_total = round(command_time_total, 3)
if response: if response: XmppMessage.send_reply(self, message, response)
encrypt_omemo = Config.get_setting_value(self, jid_bare, 'omemo') if Config.get_setting_value(self.settings, jid_bare, 'finished'):
encrypted = True if encrypt_omemo else False
if encrypted and self['xep_0384'].is_encrypted(message):
response_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, message_from, response)
if omemo_decrypted and omemo_encrypted:
# message_from = message['from']
# message_type = message['type']
XmppMessage.send_omemo(self, message_from, message_type, response_encrypted)
# XmppMessage.send_omemo_reply(self, message, response_encrypted)
else:
XmppMessage.send_reply(self, message, response)
if Config.get_setting_value(self, jid_bare, 'finished'):
response_finished = 'Finished. Total time: {}s'.format(command_time_total) response_finished = 'Finished. Total time: {}s'.format(command_time_total)
XmppMessage.send_reply(self, message, response_finished) XmppMessage.send_reply(self, message, response_finished)
@ -665,13 +610,13 @@ class XmppChat:
class XmppChatAction: class XmppChatAction:
async def send_unread_items(self, jid_bare, num: Optional[int] = None): async def send_unread_items(self, jid_bare, num=None):
""" """
Send news items as messages. Send news items as messages.
Parameters Parameters
---------- ----------
jid_bare : str jid : str
Jabber ID. Jabber ID.
num : str, optional num : str, optional
Number. The default is None. Number. The default is None.
@ -679,17 +624,14 @@ class XmppChatAction:
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid: {} num: {}'.format(function_name, jid_bare, num)) logger.debug('{}: jid: {} num: {}'.format(function_name, jid_bare, num))
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
encrypt_omemo = Config.get_setting_value(self, jid_bare, 'omemo') show_media = Config.get_setting_value(self.settings, jid_bare, 'media')
encrypted = True if encrypt_omemo else False
jid = JID(jid_bare)
show_media = Config.get_setting_value(self, jid_bare, 'media')
if not num: if not num:
num = Config.get_setting_value(self, jid_bare, 'quantum') num = Config.get_setting_value(self.settings, jid_bare, 'quantum')
else: else:
num = int(num) num = int(num)
results = sqlite.get_unread_entries(db_file, num) results = sqlite.get_unread_entries(db_file, num)
news_digest = '' news_digest = ''
media_url = None media = None
chat_type = await XmppUtilities.get_chat_type(self, jid_bare) chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
for result in results: for result in results:
ix = result[0] ix = result[0]
@ -716,92 +658,20 @@ class XmppChatAction:
# elif enclosure: # elif enclosure:
if show_media: if show_media:
if enclosure: if enclosure:
media_url = enclosure media = enclosure
else: else:
media_url = await Html.extract_image_from_html(url) media = await Html.extract_image_from_html(url)
try:
http_headers = await Http.fetch_headers(media_url) if media and news_digest:
if ('Content-Length' in http_headers): # Send textual message
if int(http_headers['Content-Length']) < 100000: XmppMessage.send(self, jid_bare, news_digest, chat_type)
media_url = None
else:
media_url = None
except Exception as e:
print(media_url)
logger.error(e)
media_url = None
if media_url and news_digest:
if encrypt_omemo:
news_digest_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, jid, news_digest)
if encrypt_omemo and omemo_encrypted:
XmppMessage.send_omemo(self, jid, chat_type, news_digest_encrypted)
else:
# Send textual message
XmppMessage.send(self, jid_bare, news_digest, chat_type)
news_digest = '' news_digest = ''
# Send media # Send media
if encrypt_omemo: XmppMessage.send_oob(self, jid_bare, media, chat_type)
cache_dir = config.get_default_cache_directory() media = None
# if not media_url.startswith('data:'):
filename = media_url.split('/').pop().split('?')[0]
if not filename: breakpoint()
pathname = os.path.join(cache_dir, filename)
# http_response = await Http.response(media_url)
http_headers = await Http.fetch_headers(media_url)
if ('Content-Length' in http_headers and
int(http_headers['Content-Length']) < 3000000):
status = await Http.fetch_media(media_url, pathname)
if status:
filesize = os.path.getsize(pathname)
media_url_new = await XmppUpload.start(
self, jid_bare, Path(pathname), filesize, encrypted=encrypted)
else:
media_url_new = media_url
else:
media_url_new = media_url
# else:
# import io, base64
# from PIL import Image
# file_content = media_url.split(',').pop()
# file_extension = media_url.split(';')[0].split(':').pop().split('/').pop()
# img = Image.open(io.BytesIO(base64.decodebytes(bytes(file_content, "utf-8"))))
# filename = 'image.' + file_extension
# pathname = os.path.join(cache_dir, filename)
# img.save(pathname)
# filesize = os.path.getsize(pathname)
# media_url_new = await XmppUpload.start(
# self, jid_bare, Path(pathname), filesize, encrypted=encrypted)
media_url_new_encrypted, omemo_encrypted = await XmppOmemo.encrypt(
self, jid, media_url_new)
if media_url_new_encrypted and omemo_encrypted:
# NOTE Tested against Gajim.
# FIXME This only works with aesgcm URLs, and it does
# not work with http URLs.
# url = saxutils.escape(url)
# AttributeError: 'Encrypted' object has no attribute 'replace'
XmppMessage.send_omemo_oob(self, jid, media_url_new_encrypted, chat_type)
else:
# NOTE Tested against Gajim.
# FIXME Jandle data: URIs.
if not media_url.startswith('data:'):
http_headers = await Http.fetch_headers(media_url)
if ('Content-Length' in http_headers and
int(http_headers['Content-Length']) > 100000):
print(http_headers['Content-Length'])
XmppMessage.send_oob(self, jid_bare, media_url, chat_type)
else:
XmppMessage.send_oob(self, jid_bare, media_url, chat_type)
media_url = None
if news_digest: if news_digest:
if encrypt_omemo: news_digest_encrypted, omemo_encrypted = await XmppOmemo.encrypt( XmppMessage.send(self, jid_bare, news_digest, chat_type)
self, jid, news_digest)
if encrypt_omemo and omemo_encrypted:
XmppMessage.send_omemo(self, jid, chat_type, news_digest_encrypted)
else:
XmppMessage.send(self, jid_bare, news_digest, chat_type)
# TODO Add while loop to assure delivery. # TODO Add while loop to assure delivery.
# print(await current_time(), ">>> ACT send_message",jid) # print(await current_time(), ">>> ACT send_message",jid)
# NOTE Do we need "if statement"? See NOTE at is_muc. # NOTE Do we need "if statement"? See NOTE at is_muc.
@ -886,7 +756,7 @@ class XmppChatAction:
summary = summary.replace(' ', ' ') summary = summary.replace(' ', ' ')
# summary = summary.replace(' ', ' ') # summary = summary.replace(' ', ' ')
summary = ' '.join(summary.split()) summary = ' '.join(summary.split())
length = Config.get_setting_value(self, jid, 'length') length = Config.get_setting_value(self.settings, jid, 'length')
length = int(length) length = int(length)
summary = summary[:length] + " […]" summary = summary[:length] + " […]"
# summary = summary.strip().split('\n') # summary = summary.strip().split('\n')
@ -900,7 +770,7 @@ class XmppChatAction:
feed_id = result[4] feed_id = result[4]
# news_item = ("\n{}\n{}\n{} [{}]\n").format(str(title), str(link), # news_item = ("\n{}\n{}\n{} [{}]\n").format(str(title), str(link),
# str(feed_title), str(ix)) # str(feed_title), str(ix))
formatting = Config.get_setting_value(self, jid, 'formatting') formatting = Config.get_setting_value(self.settings, jid, 'formatting')
news_item = formatting.format(feed_title=feed_title, news_item = formatting.format(feed_title=feed_title,
title=title, title=title,
summary=summary, summary=summary,
@ -917,9 +787,9 @@ class XmppChatTask:
async def task_message(self, jid_bare): async def task_message(self, jid_bare):
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
if jid_bare not in self.settings: if jid_bare not in self.settings:
Config.add_settings_jid(self, jid_bare, db_file) Config.add_settings_jid(self.settings, jid_bare, db_file)
while True: while True:
update_interval = Config.get_setting_value(self, jid_bare, 'interval') update_interval = Config.get_setting_value(self.settings, jid_bare, 'interval')
update_interval = 60 * int(update_interval) update_interval = 60 * int(update_interval)
last_update_time = sqlite.get_last_update_time(db_file) last_update_time = sqlite.get_last_update_time(db_file)
if last_update_time: if last_update_time:

View file

@ -31,9 +31,8 @@ NOTE
import asyncio import asyncio
from datetime import datetime from datetime import datetime
from feedparser import parse
import os import os
from pathlib import Path from feedparser import parse
import slixmpp import slixmpp
# from slixmpp.plugins.xep_0363.http_upload import FileTooBig, HTTPError, UploadServiceNotFound # from slixmpp.plugins.xep_0363.http_upload import FileTooBig, HTTPError, UploadServiceNotFound
# from slixmpp.plugins.xep_0402 import BookmarkStorage, Conference # from slixmpp.plugins.xep_0402 import BookmarkStorage, Conference
@ -44,7 +43,7 @@ import slixmpp
# from lxml import etree # from lxml import etree
import slixfeed.config as config import slixfeed.config as config
from slixfeed.config import Config, Data from slixfeed.config import Config
import slixfeed.fetch as fetch import slixfeed.fetch as fetch
from slixfeed.log import Logger from slixfeed.log import Logger
import slixfeed.sqlite as sqlite import slixfeed.sqlite as sqlite
@ -54,12 +53,11 @@ from slixfeed.version import __version__
from slixfeed.xmpp.bookmark import XmppBookmark from slixfeed.xmpp.bookmark import XmppBookmark
from slixfeed.xmpp.chat import XmppChat, XmppChatTask from slixfeed.xmpp.chat import XmppChat, XmppChatTask
from slixfeed.xmpp.connect import XmppConnect, XmppConnectTask from slixfeed.xmpp.connect import XmppConnect, XmppConnectTask
from slixfeed.xmpp.encryption import XmppOmemo
from slixfeed.xmpp.groupchat import XmppGroupchat
from slixfeed.xmpp.ipc import XmppIpcServer from slixfeed.xmpp.ipc import XmppIpcServer
from slixfeed.xmpp.iq import XmppIQ from slixfeed.xmpp.iq import XmppIQ
from slixfeed.xmpp.message import XmppMessage from slixfeed.xmpp.message import XmppMessage
from slixfeed.xmpp.muc import XmppMuc from slixfeed.xmpp.muc import XmppMuc
from slixfeed.xmpp.groupchat import XmppGroupchat
from slixfeed.xmpp.presence import XmppPresence from slixfeed.xmpp.presence import XmppPresence
import slixfeed.xmpp.profile as profile import slixfeed.xmpp.profile as profile
from slixfeed.xmpp.publish import XmppPubsub, XmppPubsubAction, XmppPubsubTask from slixfeed.xmpp.publish import XmppPubsub, XmppPubsubAction, XmppPubsubTask
@ -68,9 +66,6 @@ from slixfeed.xmpp.roster import XmppRoster
from slixfeed.xmpp.status import XmppStatusTask from slixfeed.xmpp.status import XmppStatusTask
from slixfeed.xmpp.upload import XmppUpload from slixfeed.xmpp.upload import XmppUpload
from slixfeed.xmpp.utilities import XmppUtilities from slixfeed.xmpp.utilities import XmppUtilities
from slixmpp import JID
import slixmpp_omemo
from slixmpp_omemo import PluginCouldNotLoad
import sys import sys
import time import time
@ -117,16 +112,14 @@ class XmppClient(slixmpp.ClientXMPP):
# Handler for ping # Handler for ping
self.task_ping_instance = {} self.task_ping_instance = {}
# Handler for default configuration
self.defaults = config.get_values('settings.toml')
# Handler for configuration # Handler for configuration
self.settings = {} self.settings = config.get_values('settings.toml')
# Handler for operators # Handler for operators
self.operators = config.get_values('accounts.toml', 'xmpp')['operators'] self.operators = config.get_values('accounts.toml', 'xmpp')['operators']
# self.settings = {} # self.settings = {}
# # Populate dict handler # # Populate dict handler
# Config.add_settings_default(self) # Config.add_settings_default(self.settings)
# Handlers for connection events # Handlers for connection events
self.connection_attempts = 0 self.connection_attempts = 0
@ -154,21 +147,6 @@ class XmppClient(slixmpp.ClientXMPP):
self.register_plugin('xep_0363') # HTTP File Upload self.register_plugin('xep_0363') # HTTP File Upload
self.register_plugin('xep_0402') # PEP Native Bookmarks self.register_plugin('xep_0402') # PEP Native Bookmarks
self.register_plugin('xep_0444') # Message Reactions self.register_plugin('xep_0444') # Message Reactions
try:
self.register_plugin(
'xep_0384',
{
'data_dir': Data.get_pathname_to_omemo_directory(),
},
module=slixmpp_omemo,) # OMEMO Encryption
except (PluginCouldNotLoad,):
logger.error('An error has occured when loading the OMEMO plugin.')
sys.exit(1)
try:
self.register_plugin('xep_0454')
except slixmpp.plugins.base.PluginNotFound:
logger.error('Could not load xep_0454. Ensure you have '
'\'cryptography\' from extras_require installed.')
# proxy_enabled = config.get_value('accounts', 'XMPP', 'proxy_enabled') # proxy_enabled = config.get_value('accounts', 'XMPP', 'proxy_enabled')
# if proxy_enabled == '1': # if proxy_enabled == '1':
@ -252,7 +230,7 @@ class XmppClient(slixmpp.ClientXMPP):
# TODO Test # TODO Test
async def on_groupchat_invite(self, message): async def on_groupchat_invite(self, message):
time_begin = time.time() time_begin = time.time()
jid_full = message['from'].full jid_full = str(message['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -290,7 +268,7 @@ class XmppClient(slixmpp.ClientXMPP):
# NOTE Tested with Gajim and Psi # NOTE Tested with Gajim and Psi
async def on_groupchat_direct_invite(self, message): async def on_groupchat_direct_invite(self, message):
time_begin = time.time() time_begin = time.time()
jid_full = message['from'].full jid_full = str(message['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -355,12 +333,12 @@ class XmppClient(slixmpp.ClientXMPP):
# jid_bare = result['jid'] # jid_bare = result['jid']
# if jid_bare not in self.settings: # if jid_bare not in self.settings:
# db_file = config.get_pathname_to_database(jid_bare) # db_file = config.get_pathname_to_database(jid_bare)
# Config.add_settings_jid(self, jid_bare, db_file) # Config.add_settings_jid(self.settings, jid_bare, db_file)
# await FeedTask.check_updates(self, jid_bare) # await FeedTask.check_updates(self, jid_bare)
# XmppPubsubTask.task_publish(self, jid_bare) # XmppPubsubTask.task_publish(self, jid_bare)
bookmarks = await XmppBookmark.get_bookmarks(self) bookmarks = await XmppBookmark.get_bookmarks(self)
await XmppGroupchat.autojoin(self, bookmarks) await XmppGroupchat.autojoin(self, bookmarks)
if 'ipc' in self.defaults and self.defaults['ipc']['bsd']: if 'ipc' in self.settings and self.settings['ipc']['bsd']:
# Start Inter-Process Communication # Start Inter-Process Communication
print('POSIX sockets: Initiating IPC server...') print('POSIX sockets: Initiating IPC server...')
self.ipc = asyncio.create_task(XmppIpcServer.ipc(self)) self.ipc = asyncio.create_task(XmppIpcServer.ipc(self))
@ -388,7 +366,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def on_disco_info(self, DiscoInfo): async def on_disco_info(self, DiscoInfo):
time_begin = time.time() time_begin = time.time()
jid_full = DiscoInfo['from'].full jid_full = str(DiscoInfo['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -403,14 +381,14 @@ class XmppClient(slixmpp.ClientXMPP):
async def on_message(self, message): async def on_message(self, message):
time_begin = time.time() time_begin = time.time()
jid_full = message['from'].full jid_full = str(message['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
jid_bare = message['from'].bare jid_bare = message['from'].bare
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
if jid_bare not in self.settings: if jid_bare not in self.settings:
Config.add_settings_jid(self, jid_bare, db_file) Config.add_settings_jid(self.settings, jid_bare, db_file)
if jid_bare == self.boundjid.bare: if jid_bare == self.boundjid.bare:
status_type = 'dnd' status_type = 'dnd'
status_message = ('Slixfeed is not designed to receive messages ' status_message = ('Slixfeed is not designed to receive messages '
@ -449,7 +427,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def on_changed_status(self, presence): async def on_changed_status(self, presence):
time_begin = time.time() time_begin = time.time()
jid_full = presence['from'].full jid_full = str(presence['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -474,7 +452,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def on_presence_subscribe(self, presence): async def on_presence_subscribe(self, presence):
time_begin = time.time() time_begin = time.time()
jid_full = presence['from'].full jid_full = str(presence['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -497,7 +475,7 @@ class XmppClient(slixmpp.ClientXMPP):
def on_presence_subscribed(self, presence): def on_presence_subscribed(self, presence):
time_begin = time.time() time_begin = time.time()
jid_full = presence['from'].full jid_full = str(presence['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -519,7 +497,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def on_presence_available(self, presence): async def on_presence_available(self, presence):
time_begin = time.time() time_begin = time.time()
jid_full = presence['from'].full jid_full = str(presence['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -543,7 +521,7 @@ class XmppClient(slixmpp.ClientXMPP):
def on_presence_unsubscribed(self, presence): def on_presence_unsubscribed(self, presence):
time_begin = time.time() time_begin = time.time()
jid_full = presence['from'].full jid_full = str(presence['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -564,7 +542,7 @@ class XmppClient(slixmpp.ClientXMPP):
def on_presence_unavailable(self, presence): def on_presence_unavailable(self, presence):
time_begin = time.time() time_begin = time.time()
jid_full = presence['from'].full jid_full = str(presence['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -592,7 +570,7 @@ class XmppClient(slixmpp.ClientXMPP):
# If bookmarks, remove groupchat JID into file # If bookmarks, remove groupchat JID into file
def on_presence_error(self, presence): def on_presence_error(self, presence):
time_begin = time.time() time_begin = time.time()
jid_full = presence['from'].full jid_full = str(presence['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -612,7 +590,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def on_chatstate_active(self, message): async def on_chatstate_active(self, message):
time_begin = time.time() time_begin = time.time()
jid_full = message['from'].full jid_full = str(message['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -635,7 +613,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def on_chatstate_composing(self, message): async def on_chatstate_composing(self, message):
# print('on_chatstate_composing START') # print('on_chatstate_composing START')
time_begin = time.time() time_begin = time.time()
jid_full = message['from'].full jid_full = str(message['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -658,7 +636,7 @@ class XmppClient(slixmpp.ClientXMPP):
def on_chatstate_gone(self, message): def on_chatstate_gone(self, message):
time_begin = time.time() time_begin = time.time()
jid_full = message['from'].full jid_full = str(message['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -675,7 +653,7 @@ class XmppClient(slixmpp.ClientXMPP):
def on_chatstate_inactive(self, message): def on_chatstate_inactive(self, message):
time_begin = time.time() time_begin = time.time()
jid_full = message['from'].full jid_full = str(message['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -692,7 +670,7 @@ class XmppClient(slixmpp.ClientXMPP):
def on_chatstate_paused(self, message): def on_chatstate_paused(self, message):
time_begin = time.time() time_begin = time.time()
jid_full = message['from'].full jid_full = str(message['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
message_log = '{}: jid_full: {}' message_log = '{}: jid_full: {}'
logger.debug(message_log.format(function_name, jid_full)) logger.debug(message_log.format(function_name, jid_full))
@ -854,7 +832,7 @@ class XmppClient(slixmpp.ClientXMPP):
# http://jabber.org/protocol/commands#actions # http://jabber.org/protocol/commands#actions
async def _handle_publish(self, iq, session): async def _handle_publish(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -895,7 +873,7 @@ class XmppClient(slixmpp.ClientXMPP):
return session return session
async def _handle_publish_action(self, payload, session): async def _handle_publish_action(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1003,7 +981,7 @@ class XmppClient(slixmpp.ClientXMPP):
return session return session
async def _handle_publish_db_preview(self, payload, session): async def _handle_publish_db_preview(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1111,7 +1089,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_publish_url_preview(self, payload, session): async def _handle_publish_url_preview(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1303,14 +1281,14 @@ class XmppClient(slixmpp.ClientXMPP):
return session return session
async def _handle_profile(self, iq, session): async def _handle_profile(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
jid_bare = session['from'].bare jid_bare = session['from'].bare
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
if jid_bare not in self.settings: if jid_bare not in self.settings:
Config.add_settings_jid(self, jid_bare, db_file) Config.add_settings_jid(self.settings, jid_bare, db_file)
form = self['xep_0004'].make_form('form', 'Profile') form = self['xep_0004'].make_form('form', 'Profile')
form['instructions'] = ('Displaying information\nJabber ID {}' form['instructions'] = ('Displaying information\nJabber ID {}'
.format(jid_bare)) .format(jid_bare))
@ -1334,42 +1312,42 @@ class XmppClient(slixmpp.ClientXMPP):
value=unread) value=unread)
form.add_field(ftype='fixed', form.add_field(ftype='fixed',
label='Options') label='Options')
key_archive = Config.get_setting_value(self, jid_bare, 'archive') key_archive = Config.get_setting_value(self.settings, jid_bare, 'archive')
key_archive = str(key_archive) key_archive = str(key_archive)
form.add_field(label='Archive', form.add_field(label='Archive',
ftype='text-single', ftype='text-single',
value=key_archive) value=key_archive)
key_enabled = Config.get_setting_value(self, jid_bare, 'enabled') key_enabled = Config.get_setting_value(self.settings, jid_bare, 'enabled')
key_enabled = str(key_enabled) key_enabled = str(key_enabled)
form.add_field(label='Enabled', form.add_field(label='Enabled',
ftype='text-single', ftype='text-single',
value=key_enabled) value=key_enabled)
key_interval = Config.get_setting_value(self, jid_bare, 'interval') key_interval = Config.get_setting_value(self.settings, jid_bare, 'interval')
key_interval = str(key_interval) key_interval = str(key_interval)
form.add_field(label='Interval', form.add_field(label='Interval',
ftype='text-single', ftype='text-single',
value=key_interval) value=key_interval)
key_length = Config.get_setting_value(self, jid_bare, 'length') key_length = Config.get_setting_value(self.settings, jid_bare, 'length')
key_length = str(key_length) key_length = str(key_length)
form.add_field(label='Length', form.add_field(label='Length',
ftype='text-single', ftype='text-single',
value=key_length) value=key_length)
key_media = Config.get_setting_value(self, jid_bare, 'media') key_media = Config.get_setting_value(self.settings, jid_bare, 'media')
key_media = str(key_media) key_media = str(key_media)
form.add_field(label='Media', form.add_field(label='Media',
ftype='text-single', ftype='text-single',
value=key_media) value=key_media)
key_old = Config.get_setting_value(self, jid_bare, 'old') key_old = Config.get_setting_value(self.settings, jid_bare, 'old')
key_old = str(key_old) key_old = str(key_old)
form.add_field(label='Old', form.add_field(label='Old',
ftype='text-single', ftype='text-single',
value=key_old) value=key_old)
key_quantum = Config.get_setting_value(self, jid_bare, 'quantum') key_quantum = Config.get_setting_value(self.settings, jid_bare, 'quantum')
key_quantum = str(key_quantum) key_quantum = str(key_quantum)
form.add_field(label='Quantum', form.add_field(label='Quantum',
ftype='text-single', ftype='text-single',
value=key_quantum) value=key_quantum)
update_interval = Config.get_setting_value(self, jid_bare, 'interval') update_interval = Config.get_setting_value(self.settings, jid_bare, 'interval')
update_interval = str(update_interval) update_interval = str(update_interval)
update_interval = 60 * int(update_interval) update_interval = 60 * int(update_interval)
last_update_time = sqlite.get_last_update_time(db_file) last_update_time = sqlite.get_last_update_time(db_file)
@ -1405,7 +1383,7 @@ class XmppClient(slixmpp.ClientXMPP):
return session return session
async def _handle_filters(self, iq, session): async def _handle_filters(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1478,7 +1456,7 @@ class XmppClient(slixmpp.ClientXMPP):
session. Additional, custom data may be saved session. Additional, custom data may be saved
here to persist across handler callbacks. here to persist across handler callbacks.
""" """
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1514,7 +1492,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscription_add(self, iq, session): async def _handle_subscription_add(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1577,7 +1555,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_recent(self, iq, session): async def _handle_recent(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1628,7 +1606,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_recent_result(self, payload, session): async def _handle_recent_result(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1685,7 +1663,7 @@ class XmppClient(slixmpp.ClientXMPP):
# FIXME # FIXME
async def _handle_recent_select(self, payload, session): async def _handle_recent_select(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1758,7 +1736,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscription_new(self, payload, session): async def _handle_subscription_new(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1962,7 +1940,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscription_toggle(self, payload, session): async def _handle_subscription_toggle(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -1987,7 +1965,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscription_del_complete(self, payload, session): async def _handle_subscription_del_complete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2015,7 +1993,7 @@ class XmppClient(slixmpp.ClientXMPP):
def _handle_cancel(self, payload, session): def _handle_cancel(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2028,7 +2006,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_discover(self, iq, session): async def _handle_discover(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2066,7 +2044,7 @@ class XmppClient(slixmpp.ClientXMPP):
def _handle_discover_type(self, payload, session): def _handle_discover_type(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2122,7 +2100,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_discover_category(self, payload, session): async def _handle_discover_category(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2152,7 +2130,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscriptions(self, iq, session): async def _handle_subscriptions(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2217,7 +2195,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscriptions_result(self, payload, session): async def _handle_subscriptions_result(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2311,7 +2289,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscription_tag(self, payload, session): async def _handle_subscription_tag(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2349,7 +2327,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscription_edit(self, payload, session): async def _handle_subscription_edit(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2446,7 +2424,7 @@ class XmppClient(slixmpp.ClientXMPP):
# TODO Create a new form. Do not "recycle" the last form. # TODO Create a new form. Do not "recycle" the last form.
async def _handle_subscription_complete(self, payload, session): async def _handle_subscription_complete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2512,7 +2490,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_advanced(self, iq, session): async def _handle_advanced(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2554,7 +2532,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_advanced_result(self, payload, session): async def _handle_advanced_result(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2701,7 +2679,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_about(self, iq, session): async def _handle_about(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2726,7 +2704,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_about_result(self, payload, session): async def _handle_about_result(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2790,7 +2768,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_motd(self, iq, session): async def _handle_motd(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2803,7 +2781,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_help(self, iq, session): async def _handle_help(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2844,7 +2822,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_import_complete(self, payload, session): async def _handle_import_complete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -2885,11 +2863,12 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_export_complete(self, payload, session): async def _handle_export_complete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
form = self['xep_0004'].make_form('result', 'Done') form = self['xep_0004'].make_form('result', 'Done')
form['instructions'] = 'Export has been completed successfully!'
# form['type'] = 'result' # form['type'] = 'result'
values = payload['values'] values = payload['values']
jid_bare = session['from'].bare jid_bare = session['from'].bare
@ -2901,30 +2880,17 @@ class XmppClient(slixmpp.ClientXMPP):
exts = values['filetype'] exts = values['filetype']
for ext in exts: for ext in exts:
filename = Feed.export_feeds(jid_bare, ext) filename = Feed.export_feeds(jid_bare, ext)
encrypt_omemo = Config.get_setting_value(self, jid_bare, 'omemo') url = await XmppUpload.start(self, jid_bare, filename)
encrypted = True if encrypt_omemo else False chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
url = await XmppUpload.start( XmppMessage.send_oob(self, jid_bare, url, chat_type)
self, jid_bare, Path(filename), encrypted=encrypted) url_field = form.add_field(var=ext.upper(),
if url: ftype='text-single',
form['instructions'] = 'Export has been completed successfully!' label=ext,
chat_type = await XmppUtilities.get_chat_type(self, jid_bare) value=url)
if encrypted: url_field['validate']['datatype'] = 'xs:anyURI'
url_encrypted, omemo_encrypted = await XmppOmemo.encrypt( session["has_next"] = False
self, JID(jid_bare), url) session['next'] = None
XmppMessage.send_omemo_oob(self, JID(jid_bare), url_encrypted, chat_type) session['payload'] = form
else:
XmppMessage.send_oob(self, jid_bare, url, chat_type)
url_field = form.add_field(var=ext.upper(),
ftype='text-single',
label=ext,
value=url)
url_field['validate']['datatype'] = 'xs:anyURI'
session["has_next"] = False
session['next'] = None
session['payload'] = form
else:
text_warn = 'OPML file export has been failed.'
session['notes'] = [['warn', text_warn]]
return session return session
@ -2932,12 +2898,12 @@ class XmppClient(slixmpp.ClientXMPP):
# TODO Attempt to look up for feeds of hostname of JID (i.e. scan # TODO Attempt to look up for feeds of hostname of JID (i.e. scan
# jabber.de for feeds for juliet@jabber.de) # jabber.de for feeds for juliet@jabber.de)
async def _handle_promoted(self, iq, session): async def _handle_promoted(self, iq, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
jid_bare = session['from'].bare jid_bare = session['from'].bare
jid_full = session['from'].full jid_full = str(session['from'])
chat_type = await XmppUtilities.get_chat_type(self, jid_bare) chat_type = await XmppUtilities.get_chat_type(self, jid_bare)
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type): if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
form = self['xep_0004'].make_form('form', 'Subscribe') form = self['xep_0004'].make_form('form', 'Subscribe')
@ -3005,7 +2971,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_admin_action(self, payload, session): async def _handle_admin_action(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3081,7 +3047,7 @@ class XmppClient(slixmpp.ClientXMPP):
form['instructions'] = ('Select a Publish-Subscribe service ' form['instructions'] = ('Select a Publish-Subscribe service '
'of which nodes you want to list.') 'of which nodes you want to list.')
# jid_bare = self.boundjid.bare # jid_bare = self.boundjid.bare
# enabled_state = Config.get_setting_value(self, jid_bare, 'enabled') # enabled_state = Config.get_setting_value(self.settings, jid_bare, 'enabled')
results = await XmppPubsub.get_pubsub_services(self) results = await XmppPubsub.get_pubsub_services(self)
options = form.add_field(desc='Select a PubSub service.', options = form.add_field(desc='Select a PubSub service.',
@ -3106,7 +3072,7 @@ class XmppClient(slixmpp.ClientXMPP):
ftype='fixed', ftype='fixed',
label='Jabber ID') label='Jabber ID')
# jid_bare = self.boundjid.bare # jid_bare = self.boundjid.bare
# enabled_state = Config.get_setting_value(self, jid_bare, 'enabled') # enabled_state = Config.get_setting_value(self.settings, jid_bare, 'enabled')
results = await XmppPubsub.get_pubsub_services(self) results = await XmppPubsub.get_pubsub_services(self)
for result in results + [{'jid' : self.boundjid.bare, for result in results + [{'jid' : self.boundjid.bare,
@ -3114,7 +3080,7 @@ class XmppClient(slixmpp.ClientXMPP):
jid_bare = result['jid'] jid_bare = result['jid']
name = result['name'] name = result['name']
enabled_state = Config.get_setting_value( enabled_state = Config.get_setting_value(
self, jid_bare, 'enabled') self.settings, jid_bare, 'enabled')
form.add_field(desc=jid_bare, form.add_field(desc=jid_bare,
ftype='boolean', ftype='boolean',
label=name, label=name,
@ -3130,7 +3096,7 @@ class XmppClient(slixmpp.ClientXMPP):
def _handle_nodes(self, payload, session): def _handle_nodes(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3158,7 +3124,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_nodes_action(self, payload, session): async def _handle_nodes_action(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3217,7 +3183,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_node_browse(self, payload, session): async def _handle_node_browse(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3248,7 +3214,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_item_view(self, payload, session): async def _handle_item_view(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3284,7 +3250,7 @@ class XmppClient(slixmpp.ClientXMPP):
# FIXME Undefined name 'jid_bare' # FIXME Undefined name 'jid_bare'
async def _handle_node_edit(self, payload, session): async def _handle_node_edit(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3337,7 +3303,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_nodes_purge(self, payload, session): async def _handle_nodes_purge(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3355,7 +3321,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_nodes_delete(self, payload, session): async def _handle_nodes_delete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3373,7 +3339,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_pubsub_complete(self, payload, session): async def _handle_pubsub_complete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3385,9 +3351,9 @@ class XmppClient(slixmpp.ClientXMPP):
value = values[key] value = values[key]
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
if jid_bare not in self.settings: if jid_bare not in self.settings:
Config.add_settings_jid(self, jid_bare, db_file) Config.add_settings_jid(self.settings, jid_bare, db_file)
await Config.set_setting_value( await Config.set_setting_value(self.settings, jid_bare,
self, jid_bare, db_file, 'enabled', value) db_file, 'enabled', value)
print(self.settings) print(self.settings)
text_note = 'Done.' text_note = 'Done.'
session['has_next'] = False session['has_next'] = False
@ -3398,7 +3364,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_subscribers_complete(self, payload, session): async def _handle_subscribers_complete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3446,7 +3412,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_contact_action(self, payload, session): async def _handle_contact_action(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3514,7 +3480,7 @@ class XmppClient(slixmpp.ClientXMPP):
def _handle_contacts_complete(self, payload, session): def _handle_contacts_complete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3538,7 +3504,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_bookmarks_edit(self, payload, session): async def _handle_bookmarks_edit(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3603,7 +3569,7 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_bookmarks_complete(self, payload, session): async def _handle_bookmarks_complete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3638,7 +3604,7 @@ class XmppClient(slixmpp.ClientXMPP):
session. Additional, custom data may be saved session. Additional, custom data may be saved
here to persist across handler callbacks. here to persist across handler callbacks.
""" """
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
@ -3647,10 +3613,10 @@ class XmppClient(slixmpp.ClientXMPP):
if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type): if XmppUtilities.is_access(self, jid_bare, jid_full, chat_type):
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
if jid_bare not in self.settings: if jid_bare not in self.settings:
Config.add_settings_jid(self, jid_bare, db_file) Config.add_settings_jid(self.settings, jid_bare, db_file)
form = self['xep_0004'].make_form('form', 'Settings') form = self['xep_0004'].make_form('form', 'Settings')
form['instructions'] = 'Editing settings of {}'.format(jid_bare) form['instructions'] = 'Editing settings of {}'.format(jid_bare)
value = Config.get_setting_value(self, jid_bare, 'enabled') value = Config.get_setting_value(self.settings, jid_bare, 'enabled')
value = str(value) value = str(value)
value = int(value) value = int(value)
if value: if value:
@ -3662,7 +3628,7 @@ class XmppClient(slixmpp.ClientXMPP):
label='Enabled', label='Enabled',
value=value, value=value,
var='enabled') var='enabled')
value = Config.get_setting_value(self, jid_bare, 'media') value = Config.get_setting_value(self.settings, jid_bare, 'media')
value = str(value) value = str(value)
value = int(value) value = int(value)
if value: if value:
@ -3674,7 +3640,7 @@ class XmppClient(slixmpp.ClientXMPP):
label='Display media', label='Display media',
value=value, value=value,
var='media') var='media')
value = Config.get_setting_value(self, jid_bare, 'old') value = Config.get_setting_value(self.settings, jid_bare, 'old')
value = str(value) value = str(value)
value = int(value) value = int(value)
if value: if value:
@ -3688,7 +3654,7 @@ class XmppClient(slixmpp.ClientXMPP):
label='Include old news', label='Include old news',
value=value, value=value,
var='old') var='old')
value = Config.get_setting_value(self, jid_bare, 'interval') value = Config.get_setting_value(self.settings, jid_bare, 'interval')
value = str(value) value = str(value)
value = int(value) value = int(value)
value = value/60 value = value/60
@ -3709,7 +3675,7 @@ class XmppClient(slixmpp.ClientXMPP):
i += 6 i += 6
else: else:
i += 1 i += 1
value = Config.get_setting_value(self, jid_bare, 'quantum') value = Config.get_setting_value(self.settings, jid_bare, 'quantum')
value = str(value) value = str(value)
options = form.add_field(desc='Amount of items per update.', options = form.add_field(desc='Amount of items per update.',
ftype='list-single', ftype='list-single',
@ -3723,7 +3689,7 @@ class XmppClient(slixmpp.ClientXMPP):
x = str(i) x = str(i)
options.addOption(x, x) options.addOption(x, x)
i += 1 i += 1
value = Config.get_setting_value(self, jid_bare, 'archive') value = Config.get_setting_value(self.settings, jid_bare, 'archive')
value = str(value) value = str(value)
options = form.add_field(desc='Number of news items to archive.', options = form.add_field(desc='Number of news items to archive.',
ftype='list-single', ftype='list-single',
@ -3757,14 +3723,14 @@ class XmppClient(slixmpp.ClientXMPP):
async def _handle_settings_complete(self, payload, session): async def _handle_settings_complete(self, payload, session):
jid_full = session['from'].full jid_full = str(session['from'])
function_name = sys._getframe().f_code.co_name function_name = sys._getframe().f_code.co_name
logger.debug('{}: jid_full: {}' logger.debug('{}: jid_full: {}'
.format(function_name, jid_full)) .format(function_name, jid_full))
jid_bare = session['from'].bare jid_bare = session['from'].bare
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
if jid_bare not in self.settings: if jid_bare not in self.settings:
Config.add_settings_jid(self, jid_bare, db_file) Config.add_settings_jid(self.settings, jid_bare, db_file)
# In this case (as is typical), the payload is a form # In this case (as is typical), the payload is a form
values = payload['values'] values = payload['values']
for key in values: for key in values:
@ -3783,7 +3749,7 @@ class XmppClient(slixmpp.ClientXMPP):
if val < 1: val = 1 if val < 1: val = 1
val = val * 60 val = val * 60
is_enabled = Config.get_setting_value(self, jid_bare, 'enabled') is_enabled = Config.get_setting_value(self.settings, jid_bare, 'enabled')
if (key == 'enabled' and if (key == 'enabled' and
val == 1 and val == 1 and
@ -3809,7 +3775,7 @@ class XmppClient(slixmpp.ClientXMPP):
XmppPresence.send(self, jid_bare, status_message, XmppPresence.send(self, jid_bare, status_message,
status_type=status_type) status_type=status_type)
await Config.set_setting_value(self, jid_bare, db_file, key, val) await Config.set_setting_value(self.settings, jid_bare, db_file, key, val)
val = self.settings[jid_bare][key] val = self.settings[jid_bare][key]
if key in ('enabled', 'media', 'old'): if key in ('enabled', 'media', 'old'):

View file

@ -174,8 +174,10 @@ class XmppCommands:
# the look into function "check_updates" of module "task". # the look into function "check_updates" of module "task".
# await action.scan(self, jid_bare, db_file, url) # await action.scan(self, jid_bare, db_file, url)
# if jid_bare not in self.settings: # if jid_bare not in self.settings:
# Config.add_settings_jid(self, jid_bare, db_file) # Config.add_settings_jid(self.settings, jid_bare,
# old = Config.get_setting_value(self, jid_bare, 'old') # db_file)
# old = Config.get_setting_value(self.settings, jid_bare,
# 'old')
# if old: # if old:
# # task.clean_tasks_xmpp_chat(self, jid_bare, ['status']) # # task.clean_tasks_xmpp_chat(self, jid_bare, ['status'])
# # await send_status(jid) # # await send_status(jid)
@ -232,7 +234,8 @@ class XmppCommands:
def get_archive(self, jid_bare): def get_archive(self, jid_bare):
result = Config.get_setting_value(self, jid_bare, 'archive') result = Config.get_setting_value(
self.settings, jid_bare, 'archive')
message = str(result) message = str(result)
return message return message
@ -243,9 +246,10 @@ class XmppCommands:
if val_new > 500: if val_new > 500:
message = 'Value may not be greater than 500.' message = 'Value may not be greater than 500.'
else: else:
val_old = Config.get_setting_value(self, jid_bare, 'archive') val_old = Config.get_setting_value(
self.settings, jid_bare, 'archive')
await Config.set_setting_value( await Config.set_setting_value(
self, jid_bare, db_file, 'archive', val_new) self.settings, jid_bare, db_file, 'archive', val_new)
message = ('Maximum archived items has been set to {} (was: {}).' message = ('Maximum archived items has been set to {} (was: {}).'
.format(val_new, val_old)) .format(val_new, val_old))
except: except:
@ -330,9 +334,9 @@ class XmppCommands:
def export_feeds(jid_bare, ext): def export_feeds(jid_bare, ext):
pathname = Feed.export_feeds(jid_bare, ext) filename = Feed.export_feeds(jid_bare, ext)
message = 'Feeds successfuly exported to {}.'.format(ext) message = 'Feeds successfuly exported to {}.'.format(ext)
return pathname, message return filename, message
def fetch_gemini(): def fetch_gemini():
@ -546,7 +550,8 @@ class XmppCommands:
def get_interval(self, jid_bare): def get_interval(self, jid_bare):
result = Config.get_setting_value(self, jid_bare, 'interval') result = Config.get_setting_value(
self.settings, jid_bare, 'interval')
message = str(result) message = str(result)
return message return message
@ -554,9 +559,10 @@ class XmppCommands:
async def set_interval(self, db_file, jid_bare, val): async def set_interval(self, db_file, jid_bare, val):
try: try:
val_new = int(val) val_new = int(val)
val_old = Config.get_setting_value(self, jid_bare, 'interval') val_old = Config.get_setting_value(
self.settings, jid_bare, 'interval')
await Config.set_setting_value( await Config.set_setting_value(
self, jid_bare, db_file, 'interval', val_new) self.settings, jid_bare, db_file, 'interval', val_new)
message = ('Updates will be sent every {} minutes ' message = ('Updates will be sent every {} minutes '
'(was: {}).'.format(val_new, val_old)) '(was: {}).'.format(val_new, val_old))
except Exception as e: except Exception as e:
@ -590,7 +596,8 @@ class XmppCommands:
def get_length(self, jid_bare): def get_length(self, jid_bare):
result = Config.get_setting_value(self, jid_bare, 'length') result = Config.get_setting_value(
self.settings, jid_bare, 'length')
result = str(result) result = str(result)
return result return result
@ -598,9 +605,10 @@ class XmppCommands:
async def set_length(self, db_file, jid_bare, val): async def set_length(self, db_file, jid_bare, val):
try: try:
val_new = int(val) val_new = int(val)
val_old = Config.get_setting_value(self, jid_bare, 'length') val_old = Config.get_setting_value(
self.settings, jid_bare, 'length')
await Config.set_setting_value( await Config.set_setting_value(
self, jid_bare, db_file, 'length', val_new) self.settings, jid_bare, db_file, 'length', val_new)
if not val_new: # i.e. val_new == 0 if not val_new: # i.e. val_new == 0
# TODO Add action to disable limit # TODO Add action to disable limit
message = ('Summary length limit is disabled ' message = ('Summary length limit is disabled '
@ -617,41 +625,29 @@ class XmppCommands:
async def set_media_off(self, jid_bare, db_file): async def set_media_off(self, jid_bare, db_file):
await Config.set_setting_value(self, jid_bare, db_file, 'media', 0) await Config.set_setting_value(self.settings, jid_bare, db_file, 'media', 0)
message = 'Media is disabled.' message = 'Media is disabled.'
return message return message
async def set_media_on(self, jid_bare, db_file): async def set_media_on(self, jid_bare, db_file):
await Config.set_setting_value(self, jid_bare, db_file, 'media', 1) await Config.set_setting_value(self.settings, jid_bare, db_file, 'media', 1)
message = 'Media is enabled.' message = 'Media is enabled.'
return message return message
async def set_old_off(self, jid_bare, db_file): async def set_old_off(self, jid_bare, db_file):
await Config.set_setting_value(self, jid_bare, db_file, 'old', 0) await Config.set_setting_value(self.settings, jid_bare, db_file, 'old', 0)
message = 'Only new items of newly added feeds be delivered.' message = 'Only new items of newly added feeds be delivered.'
return message return message
async def set_old_on(self, jid_bare, db_file): async def set_old_on(self, jid_bare, db_file):
await Config.set_setting_value(self, jid_bare, db_file, 'old', 1) await Config.set_setting_value(self.settings, jid_bare, db_file, 'old', 1)
message = 'All items of newly added feeds be delivered.' message = 'All items of newly added feeds be delivered.'
return message return message
async def set_omemo_off(self, jid_bare, db_file):
await Config.set_setting_value(self, jid_bare, db_file, 'omemo', 0)
message = 'OMEMO is disabled.'
return message
async def set_omemo_on(self, jid_bare, db_file):
await Config.set_setting_value(self, jid_bare, db_file, 'omemo', 1)
message = 'OMEMO is enabled.'
return message
def node_delete(self, info): def node_delete(self, info):
info = info.split(' ') info = info.split(' ')
if len(info) > 2: if len(info) > 2:
@ -691,8 +687,8 @@ class XmppCommands:
def print_options(self, jid_bare): def print_options(self, jid_bare):
message = '' message = ''
for key in self.settings[jid_bare]: for key in self.settings[jid_bare]:
val = Config.get_setting_value(self, jid_bare, key) val = Config.get_setting_value(self.settings, jid_bare, key)
# val = Config.get_setting_value(self, jid_bare, key) # val = Config.get_setting_value(self.settings, jid_bare, key)
steps = 11 - len(key) steps = 11 - len(key)
pulse = '' pulse = ''
for step in range(steps): for step in range(steps):
@ -702,7 +698,8 @@ class XmppCommands:
def get_quantum(self, jid_bare): def get_quantum(self, jid_bare):
result = Config.get_setting_value(self, jid_bare, 'quantum') result = Config.get_setting_value(
self.settings, jid_bare, 'quantum')
message = str(result) message = str(result)
return message return message
@ -710,13 +707,14 @@ class XmppCommands:
async def set_quantum(self, db_file, jid_bare, val): async def set_quantum(self, db_file, jid_bare, val):
try: try:
val_new = int(val) val_new = int(val)
val_old = Config.get_setting_value(self, jid_bare, 'quantum') val_old = Config.get_setting_value(
self.settings, jid_bare, 'quantum')
# response = ( # response = (
# 'Every update will contain {} news items.' # 'Every update will contain {} news items.'
# ).format(response) # ).format(response)
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
await Config.set_setting_value( await Config.set_setting_value(self.settings, jid_bare,
self, jid_bare, db_file, 'quantum', val_new) db_file, 'quantum', val_new)
message = ('Next update will contain {} news items (was: {}).' message = ('Next update will contain {} news items (was: {}).'
.format(val_new, val_old)) .format(val_new, val_old))
except: except:
@ -960,16 +958,17 @@ class XmppCommands:
# Tasks are classes which are passed to this function # Tasks are classes which are passed to this function
# On an occasion in which they would have returned, variable "tasks" might be called "callback" # On an occasion in which they would have returned, variable "tasks" might be called "callback"
async def scheduler_start(self, db_file, jid_bare, callbacks): async def scheduler_start(self, db_file, jid_bare, tasks):
await Config.set_setting_value(self, jid_bare, db_file, 'enabled', 1) await Config.set_setting_value(self.settings, jid_bare, db_file, 'enabled', 1)
for callback in callbacks: for task in tasks:
callback.restart_task(self, jid_bare) task.restart_task(self, jid_bare)
message = 'Updates are enabled.' message = 'Updates are enabled.'
return message return message
async def scheduler_stop(self, db_file, jid_bare): async def scheduler_stop(self, db_file, jid_bare):
await Config.set_setting_value(self, jid_bare, db_file, 'enabled', 0) await Config.set_setting_value(
self.settings, jid_bare, db_file, 'enabled', 0)
for task in ('interval', 'status'): for task in ('interval', 'status'):
if (jid_bare in self.task_manager and if (jid_bare in self.task_manager and
task in self.task_manager[jid_bare]): task in self.task_manager[jid_bare]):

View file

@ -1,180 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
TODO
1) Deprecate "add" (see above) and make it interactive.
Slixfeed: Do you still want to add this URL to subscription list?
See: case _ if command_lowercase.startswith("add"):
2) If subscription is inadequate (see XmppPresence.request), send a message that says so.
elif not self.client_roster[jid]["to"]:
breakpoint()
message.reply("Share online status to activate bot.").send()
return
3) Set timeout for moderator interaction.
If moderator interaction has been made, and moderator approves the bot, then
the bot will add the given groupchat to bookmarks; otherwise, the bot will
send a message that it was not approved and therefore leaves the groupchat.
"""
from omemo.exceptions import MissingBundleException
from slixfeed.log import Logger
from slixmpp import JID
from slixmpp.exceptions import IqTimeout, IqError
from slixmpp.stanza import Message
from slixmpp_omemo import MissingOwnKey, EncryptionPrepareException
from slixmpp_omemo import UndecidedException, UntrustedException, NoAvailableSession
logger = Logger(__name__)
# for task in main_task:
# task.cancel()
# Deprecated in favour of event "presence_available"
# if not main_task:
# await select_file()
class XmppOmemo:
async def decrypt(self, message: Message, allow_untrusted: bool = False):
jid = message['from']
try:
message_omemo_encrypted = message['omemo_encrypted']
message_body = await self['xep_0384'].decrypt_message(
message_omemo_encrypted, jid, allow_untrusted)
# decrypt_message returns Optional[str]. It is possible to get
# body-less OMEMO message (see KeyTransportMessages), currently
# used for example to send heartbeats to other devices.
if message_body is not None:
response = message_body.decode('utf8')
omemo_decrypted = True
else:
omemo_decrypted = response = None
retry = None
except (MissingOwnKey,) as exn:
# The message is missing our own key, it was not encrypted for
# us, and we can't decrypt it.
response = ('Error: Your message has not been encrypted for '
'Slixfeed (MissingOwnKey).')
omemo_decrypted = False
retry = False
logger.error(exn)
except (NoAvailableSession,) as exn:
# We received a message from that contained a session that we
# don't know about (deleted session storage, etc.). We can't
# decrypt the message, and it's going to be lost.
# Here, as we need to initiate a new encrypted session, it is
# best if we send an encrypted message directly. XXX: Is it
# where we talk about self-healing messages?
response = ('Error: Your message has not been encrypted for '
'Slixfeed (NoAvailableSession).')
omemo_decrypted = False
retry = False
logger.error(exn)
except (UndecidedException, UntrustedException) as exn:
# We received a message from an untrusted device. We can
# choose to decrypt the message nonetheless, with the
# `allow_untrusted` flag on the `decrypt_message` call, which
# we will do here. This is only possible for decryption,
# encryption will require us to decide if we trust the device
# or not. Clients _should_ indicate that the message was not
# trusted, or in undecided state, if they decide to decrypt it
# anyway.
response = (f'Error: Device "{exn.device}" is not present in the '
'trusted devices of Slixfeed.')
omemo_decrypted = False
retry = True
logger.error(exn)
# We resend, setting the `allow_untrusted` parameter to True.
# await XmppChat.process_message(self, message, allow_untrusted=True)
except (EncryptionPrepareException,) as exn:
# Slixmpp tried its best, but there were errors it couldn't
# resolve. At this point you should have seen other exceptions
# and given a chance to resolve them already.
response = ('Error: Your message has not been encrypted for '
'Slixfeed (EncryptionPrepareException).')
omemo_decrypted = False
retry = False
logger.error(exn)
except (Exception,) as exn:
response = ('Error: Your message has not been encrypted for '
'Slixfeed (Unknown).')
omemo_decrypted = False
retry = False
logger.error(exn)
raise
return response, omemo_decrypted, retry
async def encrypt(self, jid: JID, message_body):
expect_problems = {} # type: Optional[Dict[JID, List[int]]]
while True:
try:
# `encrypt_message` excepts the plaintext to be sent, a list of
# bare JIDs to encrypt to, and optionally a dict of problems to
# expect per bare JID.
#
# Note that this function returns an `<encrypted/>` object,
# and not a full Message stanza. This combined with the
# `recipients` parameter that requires for a list of JIDs,
# allows you to encrypt for 1:1 as well as groupchats (MUC).
#
# `expect_problems`: See EncryptionPrepareException handling.
recipients = [jid]
message_body = await self['xep_0384'].encrypt_message(
message_body, recipients, expect_problems)
omemo_encrypted = True
break
except UndecidedException as exn:
# The library prevents us from sending a message to an
# untrusted/undecided barejid, so we need to make a decision here.
# This is where you prompt your user to ask what to do. In
# this bot we will automatically trust undecided recipients.
await self['xep_0384'].trust(exn.bare_jid, exn.device, exn.ik)
omemo_encrypted = False
# TODO: catch NoEligibleDevicesException
except EncryptionPrepareException as exn:
# This exception is being raised when the library has tried
# all it could and doesn't know what to do anymore. It
# contains a list of exceptions that the user must resolve, or
# explicitely ignore via `expect_problems`.
# TODO: We might need to bail out here if errors are the same?
for error in exn.errors:
if isinstance(error, MissingBundleException):
# We choose to ignore MissingBundleException. It seems
# to be somewhat accepted that it's better not to
# encrypt for a device if it has problems and encrypt
# for the rest, rather than error out. The "faulty"
# device won't be able to decrypt and should display a
# generic message. The receiving end-user at this
# point can bring up the issue if it happens.
message_body = (f'Could not find keys for device '
'"{error.device}"'
f' of recipient "{error.bare_jid}". '
'Skipping.')
omemo_encrypted = False
jid = JID(error.bare_jid)
device_list = expect_problems.setdefault(jid, [])
device_list.append(error.device)
except (IqError, IqTimeout) as exn:
message_body = ('An error occured while fetching information '
'on a recipient.\n%r' % exn)
omemo_encrypted = False
except Exception as exn:
message_body = ('An error occured while attempting to encrypt'
'.\n%r' % exn)
omemo_encrypted = False
raise
return message_body, omemo_encrypted

View file

@ -34,31 +34,21 @@ class XmppGroupchat:
'bookmark {}'.format(bookmark['name'])) 'bookmark {}'.format(bookmark['name']))
alias = bookmark["nick"] alias = bookmark["nick"]
muc_jid = bookmark["jid"] muc_jid = bookmark["jid"]
# Message.printer('Joining to MUC {} ...'.format(muc_jid)) Message.printer('Joining to MUC {} ...'.format(muc_jid))
print('Joining to MUC {} ...'.format(muc_jid))
result = await XmppMuc.join(self, muc_jid, alias) result = await XmppMuc.join(self, muc_jid, alias)
match result: if result == 'ban':
case 'ban': await XmppBookmark.remove(self, muc_jid)
await XmppBookmark.remove(self, muc_jid) logger.warning('{} is banned from {}'.format(self.alias, muc_jid))
logger.warning('{} is banned from {}'.format(self.alias, muc_jid)) logger.warning('Groupchat {} has been removed from bookmarks'
logger.warning('Groupchat {} has been removed from bookmarks' .format(muc_jid))
.format(muc_jid)) else:
case 'error': logger.info('Autojoin groupchat\n'
logger.warning('An error has occured while attempting ' 'Name : {}\n'
'to join to groupchat {}' 'JID : {}\n'
.format(muc_jid)) 'Alias : {}\n'
case 'timeout': .format(bookmark["name"],
logger.warning('Timeout has reached while attempting ' bookmark["jid"],
'to join to groupchat {}' bookmark["nick"]))
.format(muc_jid))
case _:
logger.info('Autojoin groupchat\n'
'Name : {}\n'
'JID : {}\n'
'Alias : {}\n'
.format(bookmark["name"],
bookmark["jid"],
bookmark["nick"]))
elif not bookmark["jid"]: elif not bookmark["jid"]:
logger.error('JID is missing for bookmark {}' logger.error('JID is missing for bookmark {}'
.format(bookmark['name'])) .format(bookmark['name']))

View file

@ -2,7 +2,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from slixfeed.log import Logger from slixfeed.log import Logger
from slixmpp import JID
import xml.sax.saxutils as saxutils import xml.sax.saxutils as saxutils
logger = Logger(__name__) logger = Logger(__name__)
@ -40,43 +39,6 @@ class XmppMessage:
mnick=self.alias) mnick=self.alias)
def send_omemo(self, jid: JID, chat_type, response_encrypted):
jid_from = str(self.boundjid) if self.is_component else None
message = self.make_message(mto=jid, mfrom=jid_from, mtype=chat_type)
eme_ns = 'eu.siacs.conversations.axolotl'
# message['eme']['namespace'] = eme_ns
# message['eme']['name'] = self['xep_0380'].mechanisms[eme_ns]
message['eme'] = {'namespace': eme_ns}
# message['eme'] = {'name': self['xep_0380'].mechanisms[eme_ns]}
message.append(response_encrypted)
message.send()
def send_omemo_oob(self, jid: JID, url_encrypted, chat_type, aesgcm=False):
jid_from = str(self.boundjid) if self.is_component else None
# if not aesgcm: url_encrypted = saxutils.escape(url_encrypted)
message = self.make_message(mto=jid, mfrom=jid_from, mtype=chat_type)
eme_ns = 'eu.siacs.conversations.axolotl'
# message['eme']['namespace'] = eme_ns
# message['eme']['name'] = self['xep_0380'].mechanisms[eme_ns]
message['eme'] = {'namespace': eme_ns}
# message['eme'] = {'name': self['xep_0380'].mechanisms[eme_ns]}
message['oob']['url'] = url_encrypted
message.append(url_encrypted)
message.send()
# FIXME Solve this function
def send_omemo_reply(self, message, response_encrypted):
eme_ns = 'eu.siacs.conversations.axolotl'
# message['eme']['namespace'] = eme_ns
# message['eme']['name'] = self['xep_0380'].mechanisms[eme_ns]
message['eme'] = {'namespace': eme_ns}
# message['eme'] = {'name': self['xep_0380'].mechanisms[eme_ns]}
message.append(response_encrypted)
message.reply(message['body']).send()
# NOTE We might want to add more characters # NOTE We might want to add more characters
# def escape_to_xml(raw_string): # def escape_to_xml(raw_string):
# escape_map = { # escape_map = {

View file

@ -46,7 +46,7 @@ class XmppMuc:
# ) # )
logger.info('Joining groupchat\nJID : {}\n'.format(jid)) logger.info('Joining groupchat\nJID : {}\n'.format(jid))
jid_from = str(self.boundjid) if self.is_component else None jid_from = str(self.boundjid) if self.is_component else None
if not alias: alias = self.alias if alias == None: self.alias
try: try:
await self.plugin['xep_0045'].join_muc_wait(jid, await self.plugin['xep_0045'].join_muc_wait(jid,
alias, alias,

View file

@ -379,7 +379,7 @@ class XmppPubsubTask:
async def task_publish(self, jid_bare): async def task_publish(self, jid_bare):
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
if jid_bare not in self.settings: if jid_bare not in self.settings:
Config.add_settings_jid(self, jid_bare, db_file) Config.add_settings_jid(self.settings, jid_bare, db_file)
while True: while True:
await XmppPubsubAction.send_unread_items(self, jid_bare) await XmppPubsubAction.send_unread_items(self, jid_bare)
await asyncio.sleep(60 * 180) await asyncio.sleep(60 * 180)

View file

@ -28,7 +28,7 @@ class XmppStatus:
logger.debug('{}: jid: {}'.format(function_name, jid_bare)) logger.debug('{}: jid: {}'.format(function_name, jid_bare))
status_text = '📜️ Slixfeed RSS News Bot' status_text = '📜️ Slixfeed RSS News Bot'
db_file = config.get_pathname_to_database(jid_bare) db_file = config.get_pathname_to_database(jid_bare)
enabled = Config.get_setting_value(self, jid_bare, 'enabled') enabled = Config.get_setting_value(self.settings, jid_bare, 'enabled')
if enabled: if enabled:
jid_task = self.pending_tasks[jid_bare] if jid_bare in self.pending_tasks else None jid_task = self.pending_tasks[jid_bare] if jid_bare in self.pending_tasks else None
if jid_task and len(jid_task): if jid_task and len(jid_task):
@ -50,7 +50,7 @@ class XmppStatus:
status_text = '📬️ There are {} news items'.format(str(unread)) status_text = '📬️ There are {} news items'.format(str(unread))
else: else:
# print('status no news for ' + jid_bare) # print('status no news for ' + jid_bare)
status_mode = 'away' status_mode = 'available'
status_text = '📭️ No news' status_text = '📭️ No news'
else: else:
# print('status disabled for ' + jid_bare) # print('status disabled for ' + jid_bare)
@ -91,4 +91,4 @@ class XmppStatusTask:
self.task_manager[jid_bare]['status'].cancel() self.task_manager[jid_bare]['status'].cancel()
else: else:
logger.debug('No task "status" for JID {}' logger.debug('No task "status" for JID {}'
.format(jid_bare)) .format(jid_bare))

View file

@ -6,51 +6,47 @@ Based on http_upload.py example from project slixmpp
https://codeberg.org/poezio/slixmpp/src/branch/master/examples/http_upload.py https://codeberg.org/poezio/slixmpp/src/branch/master/examples/http_upload.py
""" """
from pathlib import Path
from slixfeed.log import Logger from slixfeed.log import Logger
from slixmpp import JID
from slixmpp.exceptions import IqTimeout, IqError from slixmpp.exceptions import IqTimeout, IqError
from slixmpp.plugins.xep_0363.http_upload import HTTPError from slixmpp.plugins.xep_0363.http_upload import HTTPError
import sys
from typing import Optional
logger = Logger(__name__) logger = Logger(__name__)
# import sys # import sys
class XmppUpload: class XmppUpload:
async def start(self, jid, filename: Path, size: Optional[int] = None, async def start(self, jid, filename, domain=None):
encrypted: bool = False, domain: Optional[JID] = None):
logger.info(['Uploading file %s...', filename]) logger.info(['Uploading file %s...', filename])
try: try:
upload_file = self['xep_0363'].upload_file upload_file = self['xep_0363'].upload_file
if encrypted and not self['xep_0454']: # if self.encrypted and not self['xep_0454']:
print( # print(
'The xep_0454 module isn\'t available. ' # 'The xep_0454 module isn\'t available. '
'Ensure you have \'cryptography\' ' # 'Ensure you have \'cryptography\' '
'from extras_require installed.', # 'from extras_require installed.',
file=sys.stderr, # file=sys.stderr,
) # )
url = None # return
elif encrypted: # elif self.encrypted:
upload_file = self['xep_0454'].upload_file # upload_file = self['xep_0454'].upload_file
try: try:
url = await upload_file(filename, size, domain, timeout=10,) url = await upload_file(
filename, domain, timeout=10,
)
logger.info('Upload successful!') logger.info('Upload successful!')
logger.info(['Sending file to %s', jid]) logger.info(['Sending file to %s', jid])
except HTTPError: except HTTPError:
url = None url = ('Error: It appears that this server does not support '
'HTTP File Upload.')
logger.error('It appears that this server does not support ' logger.error('It appears that this server does not support '
'HTTP File Upload.') 'HTTP File Upload.')
# raise HTTPError( # raise HTTPError(
# "This server doesn't appear to support HTTP File Upload" # "This server doesn't appear to support HTTP File Upload"
# ) # )
except IqError as e: except IqError as e:
url = None
logger.error('Could not send message') logger.error('Could not send message')
logger.error(e) logger.error(e)
except IqTimeout as e: except IqTimeout as e:
url = None
# raise TimeoutError('Could not send message in time') # raise TimeoutError('Could not send message in time')
logger.error('Could not send message in time') logger.error('Could not send message in time')
logger.error(e) logger.error(e)