Fix presence and subscription handling.
Segregate and atomize into classes.
This commit is contained in:
parent
422e0669f1
commit
00a8ed180a
18 changed files with 734 additions and 782 deletions
|
@ -24,6 +24,7 @@ TODO
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import asyncio
|
||||||
from asyncio.exceptions import IncompleteReadError
|
from asyncio.exceptions import IncompleteReadError
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from feedparser import parse
|
from feedparser import parse
|
||||||
|
@ -34,13 +35,11 @@ from lxml import html
|
||||||
import os
|
import os
|
||||||
import slixfeed.config as config
|
import slixfeed.config as config
|
||||||
import slixfeed.crawl as crawl
|
import slixfeed.crawl as crawl
|
||||||
from slixfeed.dt import (
|
|
||||||
current_date, current_time, now,
|
import slixfeed.dt as dt
|
||||||
convert_struct_time_to_iso8601,
|
|
||||||
rfc2822_to_iso8601
|
|
||||||
)
|
|
||||||
import slixfeed.fetch as fetch
|
import slixfeed.fetch as fetch
|
||||||
import slixfeed.sqlite as sqlite
|
import slixfeed.sqlite as sqlite
|
||||||
|
import slixfeed.url as uri
|
||||||
from slixfeed.url import (
|
from slixfeed.url import (
|
||||||
complete_url,
|
complete_url,
|
||||||
join_url,
|
join_url,
|
||||||
|
@ -51,7 +50,9 @@ from slixfeed.url import (
|
||||||
import slixfeed.task as task
|
import slixfeed.task as task
|
||||||
from slixfeed.xmpp.bookmark import XmppBookmark
|
from slixfeed.xmpp.bookmark import XmppBookmark
|
||||||
from slixfeed.xmpp.message import XmppMessage
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
from slixfeed.xmpp.status import XmppStatus
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
|
from slixfeed.xmpp.upload import XmppUpload
|
||||||
|
from slixfeed.xmpp.utility import get_chat_type
|
||||||
import tomllib
|
import tomllib
|
||||||
from urllib import error
|
from urllib import error
|
||||||
from urllib.parse import parse_qs, urlsplit
|
from urllib.parse import parse_qs, urlsplit
|
||||||
|
@ -122,8 +123,7 @@ async def xmpp_change_interval(self, key, val, jid, jid_file, message=None, sess
|
||||||
await sqlite.set_settings_value(db_file, [key, val])
|
await sqlite.set_settings_value(db_file, [key, val])
|
||||||
# NOTE Perhaps this should be replaced
|
# NOTE Perhaps this should be replaced
|
||||||
# by functions clean and start
|
# by functions clean and start
|
||||||
await task.refresh_task(self, jid, task.send_update,
|
await task.refresh_task(self, jid, task.send_update, key, val)
|
||||||
key, val)
|
|
||||||
response = ('Updates will be sent every {} minutes.'
|
response = ('Updates will be sent every {} minutes.'
|
||||||
.format(val))
|
.format(val))
|
||||||
else:
|
else:
|
||||||
|
@ -131,7 +131,24 @@ async def xmpp_change_interval(self, key, val, jid, jid_file, message=None, sess
|
||||||
if message:
|
if message:
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
if session:
|
if session:
|
||||||
await XmppMessage.send(self, jid, response, chat_type='chat')
|
XmppMessage.send(self, jid, response, chat_type='chat')
|
||||||
|
|
||||||
|
|
||||||
|
async def xmpp_start_updates(self, message, jid, jid_file):
|
||||||
|
key = 'enabled'
|
||||||
|
val = 1
|
||||||
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
|
if await sqlite.get_settings_value(db_file, key):
|
||||||
|
await sqlite.update_settings_value(db_file, [key, val])
|
||||||
|
else:
|
||||||
|
await sqlite.set_settings_value(db_file, [key, val])
|
||||||
|
status_type = 'available'
|
||||||
|
status_message = '💡️ Welcome back!'
|
||||||
|
XmppPresence.send(self, jid, status_message, status_type=status_type)
|
||||||
|
message_body = 'Updates are enabled.'
|
||||||
|
XmppMessage.send_reply(self, message, message_body)
|
||||||
|
await asyncio.sleep(5)
|
||||||
|
await task.start_tasks_xmpp(self, jid, ['check', 'status', 'interval'])
|
||||||
|
|
||||||
|
|
||||||
async def xmpp_stop_updates(self, message, jid, jid_file):
|
async def xmpp_stop_updates(self, message, jid, jid_file):
|
||||||
|
@ -143,11 +160,12 @@ async def xmpp_stop_updates(self, message, jid, jid_file):
|
||||||
else:
|
else:
|
||||||
await sqlite.set_settings_value(db_file, [key, val])
|
await sqlite.set_settings_value(db_file, [key, val])
|
||||||
await task.clean_tasks_xmpp(jid, ['interval', 'status'])
|
await task.clean_tasks_xmpp(jid, ['interval', 'status'])
|
||||||
response = 'Updates are disabled.'
|
message_body = 'Updates are disabled.'
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, message_body)
|
||||||
status_type = 'xa'
|
status_type = 'xa'
|
||||||
status_message = '💡️ Send "Start" to receive Jabber updates'
|
status_message = '💡️ Send "Start" to receive Jabber updates'
|
||||||
await XmppStatus.send(self, jid, status_message, status_type)
|
XmppPresence.send(self, jid, status_message, status_type=status_type)
|
||||||
|
|
||||||
|
|
||||||
def log_to_markdown(timestamp, filename, jid, message):
|
def log_to_markdown(timestamp, filename, jid, message):
|
||||||
"""
|
"""
|
||||||
|
@ -473,7 +491,7 @@ def export_to_markdown(jid, filename, results):
|
||||||
file.write(
|
file.write(
|
||||||
'\n\n* * *\n\nThis list was saved on {} from xmpp:{} using '
|
'\n\n* * *\n\nThis list was saved on {} from xmpp:{} using '
|
||||||
'[Slixfeed](https://gitgud.io/sjehuda/slixfeed)\n'.format(
|
'[Slixfeed](https://gitgud.io/sjehuda/slixfeed)\n'.format(
|
||||||
current_date(), jid))
|
dt.current_date(), jid))
|
||||||
|
|
||||||
|
|
||||||
# TODO Consider adding element jid as a pointer of import
|
# TODO Consider adding element jid as a pointer of import
|
||||||
|
@ -487,7 +505,7 @@ def export_to_opml(jid, filename, results):
|
||||||
ET.SubElement(head, "generator").text = "Slixfeed"
|
ET.SubElement(head, "generator").text = "Slixfeed"
|
||||||
ET.SubElement(head, "urlPublic").text = (
|
ET.SubElement(head, "urlPublic").text = (
|
||||||
"https://gitgud.io/sjehuda/slixfeed")
|
"https://gitgud.io/sjehuda/slixfeed")
|
||||||
time_stamp = current_time()
|
time_stamp = dt.current_time()
|
||||||
ET.SubElement(head, "dateCreated").text = time_stamp
|
ET.SubElement(head, "dateCreated").text = time_stamp
|
||||||
ET.SubElement(head, "dateModified").text = time_stamp
|
ET.SubElement(head, "dateModified").text = time_stamp
|
||||||
body = ET.SubElement(root, "body")
|
body = ET.SubElement(root, "body")
|
||||||
|
@ -548,7 +566,7 @@ async def add_feed(db_file, url):
|
||||||
if "updated_parsed" in feed["feed"].keys():
|
if "updated_parsed" in feed["feed"].keys():
|
||||||
updated = feed["feed"]["updated_parsed"]
|
updated = feed["feed"]["updated_parsed"]
|
||||||
try:
|
try:
|
||||||
updated = convert_struct_time_to_iso8601(updated)
|
updated = dt.convert_struct_time_to_iso8601(updated)
|
||||||
except:
|
except:
|
||||||
updated = ''
|
updated = ''
|
||||||
else:
|
else:
|
||||||
|
@ -594,7 +612,7 @@ async def add_feed(db_file, url):
|
||||||
if "date_published" in feed.keys():
|
if "date_published" in feed.keys():
|
||||||
updated = feed["date_published"]
|
updated = feed["date_published"]
|
||||||
try:
|
try:
|
||||||
updated = convert_struct_time_to_iso8601(updated)
|
updated = dt.convert_struct_time_to_iso8601(updated)
|
||||||
except:
|
except:
|
||||||
updated = ''
|
updated = ''
|
||||||
else:
|
else:
|
||||||
|
@ -676,7 +694,7 @@ async def scan_json(db_file, url):
|
||||||
if "date_published" in feed.keys():
|
if "date_published" in feed.keys():
|
||||||
updated = feed["date_published"]
|
updated = feed["date_published"]
|
||||||
try:
|
try:
|
||||||
updated = convert_struct_time_to_iso8601(updated)
|
updated = dt.convert_struct_time_to_iso8601(updated)
|
||||||
except:
|
except:
|
||||||
updated = ''
|
updated = ''
|
||||||
else:
|
else:
|
||||||
|
@ -697,12 +715,12 @@ async def scan_json(db_file, url):
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
if "date_published" in entry.keys():
|
if "date_published" in entry.keys():
|
||||||
date = entry["date_published"]
|
date = entry["date_published"]
|
||||||
date = rfc2822_to_iso8601(date)
|
date = dt.rfc2822_to_iso8601(date)
|
||||||
elif "date_modified" in entry.keys():
|
elif "date_modified" in entry.keys():
|
||||||
date = entry["date_modified"]
|
date = entry["date_modified"]
|
||||||
date = rfc2822_to_iso8601(date)
|
date = dt.rfc2822_to_iso8601(date)
|
||||||
else:
|
else:
|
||||||
date = now()
|
date = dt.now()
|
||||||
if "url" in entry.keys():
|
if "url" in entry.keys():
|
||||||
# link = complete_url(source, entry.link)
|
# link = complete_url(source, entry.link)
|
||||||
link = join_url(url, entry["url"])
|
link = join_url(url, entry["url"])
|
||||||
|
@ -820,10 +838,10 @@ async def view_feed(url):
|
||||||
link = "*** No link ***"
|
link = "*** No link ***"
|
||||||
if entry.has_key("published"):
|
if entry.has_key("published"):
|
||||||
date = entry.published
|
date = entry.published
|
||||||
date = rfc2822_to_iso8601(date)
|
date = dt.rfc2822_to_iso8601(date)
|
||||||
elif entry.has_key("updated"):
|
elif entry.has_key("updated"):
|
||||||
date = entry.updated
|
date = entry.updated
|
||||||
date = rfc2822_to_iso8601(date)
|
date = dt.rfc2822_to_iso8601(date)
|
||||||
else:
|
else:
|
||||||
date = "*** No date ***"
|
date = "*** No date ***"
|
||||||
response += (
|
response += (
|
||||||
|
@ -877,10 +895,10 @@ async def view_entry(url, num):
|
||||||
title = "*** No title ***"
|
title = "*** No title ***"
|
||||||
if entry.has_key("published"):
|
if entry.has_key("published"):
|
||||||
date = entry.published
|
date = entry.published
|
||||||
date = rfc2822_to_iso8601(date)
|
date = dt.rfc2822_to_iso8601(date)
|
||||||
elif entry.has_key("updated"):
|
elif entry.has_key("updated"):
|
||||||
date = entry.updated
|
date = entry.updated
|
||||||
date = rfc2822_to_iso8601(date)
|
date = dt.rfc2822_to_iso8601(date)
|
||||||
else:
|
else:
|
||||||
date = "*** No date ***"
|
date = "*** No date ***"
|
||||||
if entry.has_key("summary"):
|
if entry.has_key("summary"):
|
||||||
|
@ -965,7 +983,7 @@ async def scan(db_file, url):
|
||||||
if "updated_parsed" in feed["feed"].keys():
|
if "updated_parsed" in feed["feed"].keys():
|
||||||
updated = feed["feed"]["updated_parsed"]
|
updated = feed["feed"]["updated_parsed"]
|
||||||
try:
|
try:
|
||||||
updated = convert_struct_time_to_iso8601(updated)
|
updated = dt.convert_struct_time_to_iso8601(updated)
|
||||||
except:
|
except:
|
||||||
updated = ''
|
updated = ''
|
||||||
else:
|
else:
|
||||||
|
@ -986,12 +1004,12 @@ async def scan(db_file, url):
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
if entry.has_key("published"):
|
if entry.has_key("published"):
|
||||||
date = entry.published
|
date = entry.published
|
||||||
date = rfc2822_to_iso8601(date)
|
date = dt.rfc2822_to_iso8601(date)
|
||||||
elif entry.has_key("updated"):
|
elif entry.has_key("updated"):
|
||||||
date = entry.updated
|
date = entry.updated
|
||||||
date = rfc2822_to_iso8601(date)
|
date = dt.rfc2822_to_iso8601(date)
|
||||||
else:
|
else:
|
||||||
date = now()
|
date = dt.now()
|
||||||
if entry.has_key("link"):
|
if entry.has_key("link"):
|
||||||
# link = complete_url(source, entry.link)
|
# link = complete_url(source, entry.link)
|
||||||
link = join_url(url, entry.link)
|
link = join_url(url, entry.link)
|
||||||
|
@ -1073,6 +1091,89 @@ async def scan(db_file, url):
|
||||||
db_file, feed_id, new_entries)
|
db_file, feed_id, new_entries)
|
||||||
|
|
||||||
|
|
||||||
|
async def download_document(self, message, jid, jid_file, message_text, ix_url,
|
||||||
|
readability):
|
||||||
|
ext = ' '.join(message_text.split(' ')[1:])
|
||||||
|
ext = ext if ext else 'pdf'
|
||||||
|
url = None
|
||||||
|
error = None
|
||||||
|
response = None
|
||||||
|
if ext in ('epub', 'html', 'markdown',
|
||||||
|
'md', 'pdf', 'text', 'txt'):
|
||||||
|
match ext:
|
||||||
|
case 'markdown':
|
||||||
|
ext = 'md'
|
||||||
|
case 'text':
|
||||||
|
ext = 'txt'
|
||||||
|
status_type = 'dnd'
|
||||||
|
status_message = ('📃️ Procesing request to produce {} document...'
|
||||||
|
.format(ext.upper()))
|
||||||
|
XmppPresence.send(self, jid, status_message,
|
||||||
|
status_type=status_type)
|
||||||
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
|
cache_dir = config.get_default_cache_directory()
|
||||||
|
if ix_url:
|
||||||
|
if not os.path.isdir(cache_dir):
|
||||||
|
os.mkdir(cache_dir)
|
||||||
|
if not os.path.isdir(cache_dir + '/readability'):
|
||||||
|
os.mkdir(cache_dir + '/readability')
|
||||||
|
try:
|
||||||
|
ix = int(ix_url)
|
||||||
|
try:
|
||||||
|
url = sqlite.get_entry_url(db_file, ix)
|
||||||
|
except:
|
||||||
|
response = 'No entry with index {}'.format(ix)
|
||||||
|
except:
|
||||||
|
url = ix_url
|
||||||
|
if url:
|
||||||
|
logging.info('Original URL: {}'
|
||||||
|
.format(url))
|
||||||
|
url = uri.remove_tracking_parameters(url)
|
||||||
|
logging.info('Processed URL (tracker removal): {}'
|
||||||
|
.format(url))
|
||||||
|
url = (uri.replace_hostname(url, 'link')) or url
|
||||||
|
logging.info('Processed URL (replace hostname): {}'
|
||||||
|
.format(url))
|
||||||
|
result = await fetch.http(url)
|
||||||
|
data = result[0]
|
||||||
|
code = result[1]
|
||||||
|
if data:
|
||||||
|
title = get_document_title(data)
|
||||||
|
title = title.strip().lower()
|
||||||
|
for i in (' ', '-'):
|
||||||
|
title = title.replace(i, '_')
|
||||||
|
for i in ('?', '"', '\'', '!'):
|
||||||
|
title = title.replace(i, '')
|
||||||
|
filename = os.path.join(
|
||||||
|
cache_dir, 'readability',
|
||||||
|
title + '_' + dt.timestamp() + '.' + ext)
|
||||||
|
error = generate_document(data, url, ext, filename,
|
||||||
|
readability)
|
||||||
|
if error:
|
||||||
|
response = ('> {}\n'
|
||||||
|
'Failed to export {}. Reason: {}'
|
||||||
|
.format(url, ext.upper(), error))
|
||||||
|
else:
|
||||||
|
url = await XmppUpload.start(self, jid,
|
||||||
|
filename)
|
||||||
|
chat_type = await get_chat_type(self, jid)
|
||||||
|
XmppMessage.send_oob(self, jid, url, chat_type)
|
||||||
|
else:
|
||||||
|
response = ('> {}\n'
|
||||||
|
'Failed to fetch URL. Reason: {}'
|
||||||
|
.format(url, code))
|
||||||
|
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||||
|
else:
|
||||||
|
response = 'Missing entry index number.'
|
||||||
|
else:
|
||||||
|
response = ('Unsupported filetype.\n'
|
||||||
|
'Try: epub, html, md (markdown), '
|
||||||
|
'pdf, or txt (text)')
|
||||||
|
if response:
|
||||||
|
logging.warning('Error for URL {}: {}'.format(url, error))
|
||||||
|
XmppMessage.send_reply(self, message, response)
|
||||||
|
|
||||||
|
|
||||||
def get_document_title(data):
|
def get_document_title(data):
|
||||||
try:
|
try:
|
||||||
document = Document(data)
|
document = Document(data)
|
||||||
|
@ -1083,14 +1184,17 @@ def get_document_title(data):
|
||||||
return title
|
return title
|
||||||
|
|
||||||
|
|
||||||
def generate_document(data, url, ext, filename):
|
def generate_document(data, url, ext, filename, readability=False):
|
||||||
error = None
|
error = None
|
||||||
try:
|
if readability:
|
||||||
document = Document(data)
|
try:
|
||||||
content = document.summary()
|
document = Document(data)
|
||||||
except:
|
content = document.summary()
|
||||||
|
except:
|
||||||
|
content = data
|
||||||
|
logging.warning('Check that package readability is installed.')
|
||||||
|
else:
|
||||||
content = data
|
content = data
|
||||||
logging.warning('Check that package readability is installed.')
|
|
||||||
match ext:
|
match ext:
|
||||||
case "epub":
|
case "epub":
|
||||||
error = generate_epub(content, filename)
|
error = generate_epub(content, filename)
|
||||||
|
@ -1319,7 +1423,7 @@ async def remove_nonexistent_entries(db_file, url, feed):
|
||||||
# print("compare11:", title, link, time)
|
# print("compare11:", title, link, time)
|
||||||
# print("compare22:", entry_title, entry_link, timestamp)
|
# print("compare22:", entry_title, entry_link, timestamp)
|
||||||
# print("============")
|
# print("============")
|
||||||
time = rfc2822_to_iso8601(entry.published)
|
time = dt.rfc2822_to_iso8601(entry.published)
|
||||||
if (entry_title == title and
|
if (entry_title == title and
|
||||||
entry_link == link and
|
entry_link == link and
|
||||||
timestamp == time):
|
timestamp == time):
|
||||||
|
@ -1423,7 +1527,7 @@ async def remove_nonexistent_entries_json(db_file, url, feed):
|
||||||
link = url
|
link = url
|
||||||
# "date_published" "date_modified"
|
# "date_published" "date_modified"
|
||||||
if entry.has_key("date_published") and timestamp:
|
if entry.has_key("date_published") and timestamp:
|
||||||
time = rfc2822_to_iso8601(entry["date_published"])
|
time = dt.rfc2822_to_iso8601(entry["date_published"])
|
||||||
if (entry_title == title and
|
if (entry_title == title and
|
||||||
entry_link == link and
|
entry_link == link and
|
||||||
timestamp == time):
|
timestamp == time):
|
||||||
|
|
|
@ -52,9 +52,14 @@ Send all items of newly added feeds.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[document]
|
[document]
|
||||||
get = """
|
content = """
|
||||||
get <id> <type>
|
content <id>/<url> <type>
|
||||||
Send an article as file. Specify <id> and <type>.
|
Send a readability (arc90) version of an article as file. Specify <id> or <url> and <type>.
|
||||||
|
Supported types are ePUB, HTML, MD and PDF (default).
|
||||||
|
"""
|
||||||
|
page = """
|
||||||
|
page <id>/<url> <type>
|
||||||
|
Send an article as file. Specify <id> or <url> and <type>.
|
||||||
Supported types are ePUB, HTML, MD and PDF (default).
|
Supported types are ePUB, HTML, MD and PDF (default).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ Kevin Smith <isode.com> (Swift IM, Wales), \
|
||||||
Luis Henrique Mello (SalixOS, Brazil), \
|
Luis Henrique Mello (SalixOS, Brazil), \
|
||||||
magicfelix, \
|
magicfelix, \
|
||||||
Markus Muttilainen (SalixOS), \
|
Markus Muttilainen (SalixOS), \
|
||||||
|
Martin <debacle@debian.org> (Debian, Germany), \
|
||||||
Mathieu Pasquet (slixmpp, France), \
|
Mathieu Pasquet (slixmpp, France), \
|
||||||
Maxime Buquet (slixmpp, France), \
|
Maxime Buquet (slixmpp, France), \
|
||||||
Phillip Watkins (United Kingdom, SalixOS), \
|
Phillip Watkins (United Kingdom, SalixOS), \
|
||||||
|
|
|
@ -47,9 +47,10 @@ import slixfeed.config as config
|
||||||
# from slixfeed.dt import current_time
|
# from slixfeed.dt import current_time
|
||||||
import slixfeed.sqlite as sqlite
|
import slixfeed.sqlite as sqlite
|
||||||
# from xmpp import Slixfeed
|
# from xmpp import Slixfeed
|
||||||
import slixfeed.xmpp.client as xmpp
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
import slixfeed.xmpp.connect as connect
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
import slixfeed.xmpp.utility as utility
|
from slixfeed.xmpp.connect import XmppConnect
|
||||||
|
from slixfeed.xmpp.utility import get_chat_type
|
||||||
import time
|
import time
|
||||||
|
|
||||||
main_task = []
|
main_task = []
|
||||||
|
@ -70,12 +71,12 @@ loop = asyncio.get_event_loop()
|
||||||
|
|
||||||
|
|
||||||
def ping_task(self):
|
def ping_task(self):
|
||||||
global ping_task
|
global ping_task_instance
|
||||||
try:
|
try:
|
||||||
ping_task.cancel()
|
ping_task_instance.cancel()
|
||||||
except:
|
except:
|
||||||
logging.info('No ping task to cancel.')
|
logging.info('No ping task to cancel.')
|
||||||
ping_task = asyncio.create_task(connect.ping(self))
|
ping_task_instance = asyncio.create_task(XmppConnect.ping(self))
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
@ -102,7 +103,7 @@ async def start_tasks_xmpp(self, jid, tasks=None):
|
||||||
logging.debug('KeyError:', str(e))
|
logging.debug('KeyError:', str(e))
|
||||||
logging.info('Creating new task manager for JID {}'.format(jid))
|
logging.info('Creating new task manager for JID {}'.format(jid))
|
||||||
if not tasks:
|
if not tasks:
|
||||||
tasks = ['interval', 'status', 'check']
|
tasks = ['status', 'check', 'interval']
|
||||||
logging.info('Stopping tasks {} for JID {}'.format(tasks, jid))
|
logging.info('Stopping tasks {} for JID {}'.format(tasks, jid))
|
||||||
for task in tasks:
|
for task in tasks:
|
||||||
# if task_manager[jid][task]:
|
# if task_manager[jid][task]:
|
||||||
|
@ -201,7 +202,7 @@ async def send_update(self, jid, num=None):
|
||||||
results = await sqlite.get_unread_entries(db_file, num)
|
results = await sqlite.get_unread_entries(db_file, num)
|
||||||
news_digest = ''
|
news_digest = ''
|
||||||
media = None
|
media = None
|
||||||
chat_type = await utility.get_chat_type(self, jid)
|
chat_type = await get_chat_type(self, jid)
|
||||||
for result in results:
|
for result in results:
|
||||||
ix = result[0]
|
ix = result[0]
|
||||||
title_e = result[1]
|
title_e = result[1]
|
||||||
|
@ -230,24 +231,10 @@ async def send_update(self, jid, num=None):
|
||||||
|
|
||||||
if media and news_digest:
|
if media and news_digest:
|
||||||
# Send textual message
|
# Send textual message
|
||||||
xmpp.Slixfeed.send_message(
|
XmppMessage.send(self, jid, news_digest, chat_type)
|
||||||
self,
|
|
||||||
mto=jid,
|
|
||||||
mfrom=self.boundjid.bare,
|
|
||||||
mbody=news_digest,
|
|
||||||
mtype=chat_type
|
|
||||||
)
|
|
||||||
news_digest = ''
|
news_digest = ''
|
||||||
# Send media
|
# Send media
|
||||||
message = xmpp.Slixfeed.make_message(
|
XmppMessage.send_oob(self, jid, media, chat_type)
|
||||||
self,
|
|
||||||
mto=jid,
|
|
||||||
mfrom=self.boundjid.bare,
|
|
||||||
mbody=media,
|
|
||||||
mtype=chat_type
|
|
||||||
)
|
|
||||||
message['oob']['url'] = media
|
|
||||||
message.send()
|
|
||||||
media = None
|
media = None
|
||||||
|
|
||||||
if news_digest:
|
if news_digest:
|
||||||
|
@ -256,13 +243,8 @@ async def send_update(self, jid, num=None):
|
||||||
# NOTE Do we need "if statement"? See NOTE at is_muc.
|
# NOTE Do we need "if statement"? See NOTE at is_muc.
|
||||||
if chat_type in ('chat', 'groupchat'):
|
if chat_type in ('chat', 'groupchat'):
|
||||||
# TODO Provide a choice (with or without images)
|
# TODO Provide a choice (with or without images)
|
||||||
xmpp.Slixfeed.send_message(
|
XmppMessage.send(self, jid, news_digest, chat_type)
|
||||||
self,
|
# See XEP-0367
|
||||||
mto=jid,
|
|
||||||
mfrom=self.boundjid.bare,
|
|
||||||
mbody=news_digest,
|
|
||||||
mtype=chat_type
|
|
||||||
)
|
|
||||||
# if media:
|
# if media:
|
||||||
# # message = xmpp.Slixfeed.make_message(
|
# # message = xmpp.Slixfeed.make_message(
|
||||||
# # self, mto=jid, mbody=new, mtype=chat_type)
|
# # self, mto=jid, mbody=new, mtype=chat_type)
|
||||||
|
@ -340,13 +322,7 @@ async def send_status(self, jid):
|
||||||
|
|
||||||
# breakpoint()
|
# breakpoint()
|
||||||
# print(await current_time(), status_text, "for", jid)
|
# print(await current_time(), status_text, "for", jid)
|
||||||
xmpp.Slixfeed.send_presence(
|
XmppPresence.send(self, jid, status_text, status_type=status_mode)
|
||||||
self,
|
|
||||||
pto=jid,
|
|
||||||
pfrom=self.boundjid.bare,
|
|
||||||
pshow=status_mode,
|
|
||||||
pstatus=status_text
|
|
||||||
)
|
|
||||||
# await asyncio.sleep(60 * 20)
|
# await asyncio.sleep(60 * 20)
|
||||||
await refresh_task(self, jid, send_status, 'status', '90')
|
await refresh_task(self, jid, send_status, 'status', '90')
|
||||||
# loop.call_at(
|
# loop.call_at(
|
||||||
|
|
|
@ -77,13 +77,8 @@ def replace_hostname(url, url_type):
|
||||||
parted_proxy_url = urlsplit(proxy_url)
|
parted_proxy_url = urlsplit(proxy_url)
|
||||||
protocol_new = parted_proxy_url.scheme
|
protocol_new = parted_proxy_url.scheme
|
||||||
hostname_new = parted_proxy_url.netloc
|
hostname_new = parted_proxy_url.netloc
|
||||||
url_new = urlunsplit([
|
url_new = urlunsplit([protocol_new, hostname_new,
|
||||||
protocol_new,
|
pathname, queries, fragment])
|
||||||
hostname_new,
|
|
||||||
pathname,
|
|
||||||
queries,
|
|
||||||
fragment
|
|
||||||
])
|
|
||||||
response = fetch.http_response(url_new)
|
response = fetch.http_response(url_new)
|
||||||
if (response and
|
if (response and
|
||||||
response.status_code == 200 and
|
response.status_code == 200 and
|
||||||
|
@ -96,8 +91,11 @@ def replace_hostname(url, url_type):
|
||||||
proxies_file = config_dir + '/proxies.toml'
|
proxies_file = config_dir + '/proxies.toml'
|
||||||
if not os.path.isfile(proxies_obsolete_file):
|
if not os.path.isfile(proxies_obsolete_file):
|
||||||
config.create_skeleton(proxies_file)
|
config.create_skeleton(proxies_file)
|
||||||
config.backup_obsolete(proxies_obsolete_file, proxy_name, proxy_type, proxy_url)
|
config.backup_obsolete(proxies_obsolete_file,
|
||||||
config.update_proxies(proxies_file, proxy_name, proxy_type, proxy_url)
|
proxy_name, proxy_type,
|
||||||
|
proxy_url)
|
||||||
|
config.update_proxies(proxies_file, proxy_name,
|
||||||
|
proxy_type, proxy_url)
|
||||||
url_new = None
|
url_new = None
|
||||||
else:
|
else:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
|
@ -132,13 +130,7 @@ def remove_tracking_parameters(url):
|
||||||
for tracker in trackers:
|
for tracker in trackers:
|
||||||
if tracker in queries: del queries[tracker]
|
if tracker in queries: del queries[tracker]
|
||||||
queries_new = urlencode(queries, doseq=True)
|
queries_new = urlencode(queries, doseq=True)
|
||||||
url = urlunsplit([
|
url = urlunsplit([protocol, hostname, pathname, queries_new, fragment])
|
||||||
protocol,
|
|
||||||
hostname,
|
|
||||||
pathname,
|
|
||||||
queries_new,
|
|
||||||
fragment
|
|
||||||
])
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,13 +149,8 @@ def feed_to_http(url):
|
||||||
URL.
|
URL.
|
||||||
"""
|
"""
|
||||||
par_url = urlsplit(url)
|
par_url = urlsplit(url)
|
||||||
new_url = urlunsplit([
|
new_url = urlunsplit(['http', par_url.netloc, par_url.path, par_url.query,
|
||||||
'http',
|
par_url.fragment])
|
||||||
par_url.netloc,
|
|
||||||
par_url.path,
|
|
||||||
par_url.query,
|
|
||||||
par_url.fragment
|
|
||||||
])
|
|
||||||
return new_url
|
return new_url
|
||||||
|
|
||||||
|
|
||||||
|
@ -215,21 +202,13 @@ def complete_url(source, link):
|
||||||
return link
|
return link
|
||||||
if link.startswith('//'):
|
if link.startswith('//'):
|
||||||
if parted_link.netloc and parted_link.path:
|
if parted_link.netloc and parted_link.path:
|
||||||
new_link = urlunsplit([
|
new_link = urlunsplit([parted_feed.scheme, parted_link.netloc,
|
||||||
parted_feed.scheme,
|
parted_link.path, parted_link.query,
|
||||||
parted_link.netloc,
|
parted_link.fragment])
|
||||||
parted_link.path,
|
|
||||||
parted_link.query,
|
|
||||||
parted_link.fragment
|
|
||||||
])
|
|
||||||
elif link.startswith('/'):
|
elif link.startswith('/'):
|
||||||
new_link = urlunsplit([
|
new_link = urlunsplit([parted_feed.scheme, parted_feed.netloc,
|
||||||
parted_feed.scheme,
|
parted_link.path, parted_link.query,
|
||||||
parted_feed.netloc,
|
parted_link.fragment])
|
||||||
parted_link.path,
|
|
||||||
parted_link.query,
|
|
||||||
parted_link.fragment
|
|
||||||
])
|
|
||||||
elif link.startswith('../'):
|
elif link.startswith('../'):
|
||||||
pathlink = parted_link.path.split('/')
|
pathlink = parted_link.path.split('/')
|
||||||
pathfeed = parted_feed.path.split('/')
|
pathfeed = parted_feed.path.split('/')
|
||||||
|
@ -246,13 +225,9 @@ def complete_url(source, link):
|
||||||
break
|
break
|
||||||
pathlink = '/'.join(pathlink)
|
pathlink = '/'.join(pathlink)
|
||||||
pathfeed.extend([pathlink])
|
pathfeed.extend([pathlink])
|
||||||
new_link = urlunsplit([
|
new_link = urlunsplit([parted_feed.scheme, parted_feed.netloc,
|
||||||
parted_feed.scheme,
|
'/'.join(pathfeed), parted_link.query,
|
||||||
parted_feed.netloc,
|
parted_link.fragment])
|
||||||
'/'.join(pathfeed),
|
|
||||||
parted_link.query,
|
|
||||||
parted_link.fragment
|
|
||||||
])
|
|
||||||
else:
|
else:
|
||||||
pathlink = parted_link.path.split('/')
|
pathlink = parted_link.path.split('/')
|
||||||
pathfeed = parted_feed.path.split('/')
|
pathfeed = parted_feed.path.split('/')
|
||||||
|
@ -262,13 +237,9 @@ def complete_url(source, link):
|
||||||
pathfeed.pop()
|
pathfeed.pop()
|
||||||
pathlink = '/'.join(pathlink)
|
pathlink = '/'.join(pathlink)
|
||||||
pathfeed.extend([pathlink])
|
pathfeed.extend([pathlink])
|
||||||
new_link = urlunsplit([
|
new_link = urlunsplit([parted_feed.scheme, parted_feed.netloc,
|
||||||
parted_feed.scheme,
|
'/'.join(pathfeed), parted_link.query,
|
||||||
parted_feed.netloc,
|
parted_link.fragment])
|
||||||
'/'.join(pathfeed),
|
|
||||||
parted_link.query,
|
|
||||||
parted_link.fragment
|
|
||||||
])
|
|
||||||
return new_link
|
return new_link
|
||||||
|
|
||||||
|
|
||||||
|
@ -333,13 +304,7 @@ def trim_url(url):
|
||||||
fragment = parted_url.fragment
|
fragment = parted_url.fragment
|
||||||
while '//' in pathname:
|
while '//' in pathname:
|
||||||
pathname = pathname.replace('//', '/')
|
pathname = pathname.replace('//', '/')
|
||||||
url = urlunsplit([
|
url = urlunsplit([protocol, hostname, pathname, queries, fragment])
|
||||||
protocol,
|
|
||||||
hostname,
|
|
||||||
pathname,
|
|
||||||
queries,
|
|
||||||
fragment
|
|
||||||
])
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,9 @@ class XmppBookmark:
|
||||||
bookmarks = Bookmarks()
|
bookmarks = Bookmarks()
|
||||||
mucs.extend([muc_jid])
|
mucs.extend([muc_jid])
|
||||||
for muc in mucs:
|
for muc in mucs:
|
||||||
bookmarks.add_conference(
|
bookmarks.add_conference(muc,
|
||||||
muc,
|
self.alias,
|
||||||
self.alias,
|
autojoin=True)
|
||||||
autojoin=True
|
|
||||||
)
|
|
||||||
await self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
await self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
||||||
# bookmarks = Bookmarks()
|
# bookmarks = Bookmarks()
|
||||||
# await self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
# await self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
||||||
|
@ -61,9 +59,7 @@ class XmppBookmark:
|
||||||
bookmarks = Bookmarks()
|
bookmarks = Bookmarks()
|
||||||
mucs.remove(muc_jid)
|
mucs.remove(muc_jid)
|
||||||
for muc in mucs:
|
for muc in mucs:
|
||||||
bookmarks.add_conference(
|
bookmarks.add_conference(muc,
|
||||||
muc,
|
self.alias,
|
||||||
self.alias,
|
autojoin=True)
|
||||||
autojoin=True
|
|
||||||
)
|
|
||||||
await self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
await self.plugin['xep_0048'].set_bookmarks(bookmarks)
|
||||||
|
|
|
@ -63,15 +63,15 @@ from slixmpp.plugins.xep_0048.stanza import Bookmarks
|
||||||
import slixfeed.config as config
|
import slixfeed.config as config
|
||||||
import slixfeed.sqlite as sqlite
|
import slixfeed.sqlite as sqlite
|
||||||
from slixfeed.xmpp.bookmark import XmppBookmark
|
from slixfeed.xmpp.bookmark import XmppBookmark
|
||||||
import slixfeed.xmpp.connect as connect
|
from slixfeed.xmpp.connect import XmppConnect
|
||||||
import slixfeed.xmpp.muc as muc
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
|
from slixfeed.xmpp.muc import XmppGroupchat
|
||||||
import slixfeed.xmpp.process as process
|
import slixfeed.xmpp.process as process
|
||||||
import slixfeed.xmpp.profile as profile
|
import slixfeed.xmpp.profile as profile
|
||||||
import slixfeed.xmpp.roster as roster
|
from slixfeed.xmpp.roster import XmppRoster
|
||||||
# import slixfeed.xmpp.service as service
|
# import slixfeed.xmpp.service as service
|
||||||
import slixfeed.xmpp.state as state
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
import slixfeed.xmpp.status as status
|
from slixfeed.xmpp.utility import get_chat_type
|
||||||
import slixfeed.xmpp.utility as utility
|
|
||||||
|
|
||||||
main_task = []
|
main_task = []
|
||||||
jid_tasker = {}
|
jid_tasker = {}
|
||||||
|
@ -146,8 +146,8 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
|
|
||||||
self.add_event_handler("reactions",
|
self.add_event_handler("reactions",
|
||||||
self.on_reactions)
|
self.on_reactions)
|
||||||
self.add_event_handler("presence_error",
|
# self.add_event_handler("presence_error",
|
||||||
self.on_presence_error)
|
# self.on_presence_error)
|
||||||
self.add_event_handler("presence_subscribe",
|
self.add_event_handler("presence_subscribe",
|
||||||
self.on_presence_subscribe)
|
self.on_presence_subscribe)
|
||||||
self.add_event_handler("presence_subscribed",
|
self.add_event_handler("presence_subscribed",
|
||||||
|
@ -161,43 +161,59 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
# handlers for connection events
|
# handlers for connection events
|
||||||
self.connection_attempts = 0
|
self.connection_attempts = 0
|
||||||
self.max_connection_attempts = 10
|
self.max_connection_attempts = 10
|
||||||
self.add_event_handler("connection_failed", self.on_connection_failed)
|
self.add_event_handler('connection_failed',
|
||||||
self.add_event_handler("session_end", self.on_session_end)
|
self.on_connection_failed)
|
||||||
|
self.add_event_handler('session_end',
|
||||||
|
self.on_session_end)
|
||||||
|
|
||||||
|
|
||||||
# TODO Test
|
# TODO Test
|
||||||
async def on_groupchat_invite(self, message):
|
async def on_groupchat_invite(self, message):
|
||||||
logging.warning("on_groupchat_invite")
|
logging.warning("on_groupchat_invite")
|
||||||
inviter = message["from"].bare
|
inviter = message['from'].bare
|
||||||
muc_jid = message['groupchat_invite']['jid']
|
muc_jid = message['groupchat_invite']['jid']
|
||||||
await muc.join(self, inviter, muc_jid)
|
|
||||||
await XmppBookmark.add(self, muc_jid)
|
await XmppBookmark.add(self, muc_jid)
|
||||||
|
await XmppGroupchat.join(self, inviter, muc_jid)
|
||||||
|
message_body = ('Greetings!\n'
|
||||||
|
'I am {}, the news anchor.\n'
|
||||||
|
'My job is to bring you the latest '
|
||||||
|
'news from sources you provide me with.\n'
|
||||||
|
'You may always reach me via xmpp:{}?message'
|
||||||
|
.format(self.alias, self.boundjid.bare))
|
||||||
|
XmppMessage.send(self, muc_jid, message_body, 'groupchat')
|
||||||
|
|
||||||
|
|
||||||
# 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):
|
||||||
inviter = message["from"].bare
|
inviter = message['from'].bare
|
||||||
muc_jid = message['groupchat_invite']['jid']
|
muc_jid = message['groupchat_invite']['jid']
|
||||||
await muc.join(self, inviter, muc_jid)
|
|
||||||
await XmppBookmark.add(self, muc_jid)
|
await XmppBookmark.add(self, muc_jid)
|
||||||
|
await XmppGroupchat.join(self, inviter, muc_jid)
|
||||||
|
message_body = ('Greetings!\n'
|
||||||
|
'I am {}, the news anchor.\n'
|
||||||
|
'My job is to bring you the latest '
|
||||||
|
'news from sources you provide me with.\n'
|
||||||
|
'You may always reach me via xmpp:{}?message'
|
||||||
|
.format(self.alias, self.boundjid.bare))
|
||||||
|
XmppMessage.send(self, muc_jid, message_body, 'groupchat')
|
||||||
|
|
||||||
|
|
||||||
async def on_session_end(self, event):
|
async def on_session_end(self, event):
|
||||||
message = "Session has ended."
|
message = 'Session has ended.'
|
||||||
await connect.recover_connection(self, message)
|
await XmppConnect.recover(self, message)
|
||||||
|
|
||||||
|
|
||||||
async def on_connection_failed(self, event):
|
async def on_connection_failed(self, event):
|
||||||
message = "Connection has failed. Reason: {}".format(event)
|
message = 'Connection has failed. Reason: {}'.format(event)
|
||||||
await connect.recover_connection(self, message)
|
await XmppConnect.recover(self, message)
|
||||||
|
|
||||||
|
|
||||||
async def on_session_start(self, event):
|
async def on_session_start(self, event):
|
||||||
self.send_presence()
|
self.send_presence()
|
||||||
await self["xep_0115"].update_caps()
|
await self['xep_0115'].update_caps()
|
||||||
await self.get_roster()
|
await self.get_roster()
|
||||||
await muc.autojoin(self)
|
await XmppGroupchat.autojoin(self)
|
||||||
profile.set_identity(self, "client")
|
profile.set_identity(self, 'client')
|
||||||
await profile.update(self)
|
await profile.update(self)
|
||||||
task.ping_task(self)
|
task.ping_task(self)
|
||||||
|
|
||||||
|
@ -210,9 +226,9 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
|
|
||||||
async def on_session_resumed(self, event):
|
async def on_session_resumed(self, event):
|
||||||
self.send_presence()
|
self.send_presence()
|
||||||
self["xep_0115"].update_caps()
|
self['xep_0115'].update_caps()
|
||||||
await muc.autojoin(self)
|
await XmppGroupchat.autojoin(self)
|
||||||
profile.set_identity(self, "client")
|
profile.set_identity(self, 'client')
|
||||||
|
|
||||||
# Service.commands(self)
|
# Service.commands(self)
|
||||||
# Service.reactions(self)
|
# Service.reactions(self)
|
||||||
|
@ -224,9 +240,16 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
# TODO Request for subscription
|
# TODO Request for subscription
|
||||||
async def on_message(self, message):
|
async def on_message(self, message):
|
||||||
jid = message["from"].bare
|
jid = message["from"].bare
|
||||||
if "chat" == await utility.get_chat_type(self, jid):
|
if (await get_chat_type(self, jid) == 'chat' and
|
||||||
await roster.add(self, jid)
|
not self.client_roster[jid]['to']):
|
||||||
await state.request(self, jid)
|
XmppPresence.subscribe(self, jid)
|
||||||
|
await XmppRoster.add(self, jid)
|
||||||
|
status_message = '✒️ Share online status to receive updates'
|
||||||
|
XmppPresence.send(self, jid, status_message)
|
||||||
|
message_subject = 'RSS News Bot'
|
||||||
|
message_body = 'Share online status to receive updates.'
|
||||||
|
XmppMessage.send_headline(self, jid, message_subject, message_body,
|
||||||
|
'chat')
|
||||||
await process.message(self, message)
|
await process.message(self, message)
|
||||||
# chat_type = message["type"]
|
# chat_type = message["type"]
|
||||||
# message_body = message["body"]
|
# message_body = message["body"]
|
||||||
|
@ -242,31 +265,54 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_subscribe(self, presence):
|
async def on_presence_subscribe(self, presence):
|
||||||
jid = presence["from"].bare
|
jid = presence['from'].bare
|
||||||
await state.request(self, jid)
|
if not self.client_roster[jid]['to']:
|
||||||
|
XmppPresence.subscribe(self, jid)
|
||||||
|
await XmppRoster.add(self, jid)
|
||||||
|
status_message = '✒️ Share online status to receive updates'
|
||||||
|
XmppPresence.send(self, jid, status_message)
|
||||||
|
message_subject = 'RSS News Bot'
|
||||||
|
message_body = 'Share online status to receive updates.'
|
||||||
|
XmppMessage.send_headline(self, jid, message_subject, message_body,
|
||||||
|
'chat')
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_subscribed(self, presence):
|
async def on_presence_subscribed(self, presence):
|
||||||
jid = presence["from"].bare
|
jid = presence['from'].bare
|
||||||
process.greet(self, jid)
|
message_subject = 'RSS News Bot'
|
||||||
|
message_body = ('Greetings!\n'
|
||||||
|
'I am {}, the news anchor.\n'
|
||||||
|
'My job is to bring you the latest '
|
||||||
|
'news from sources you provide me with.\n'
|
||||||
|
'You may always reach me via xmpp:{}?message'
|
||||||
|
.format(self.alias, self.boundjid.bare))
|
||||||
|
XmppMessage.send_headline(self, jid, message_subject, message_body,
|
||||||
|
'chat')
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_available(self, presence):
|
async def on_presence_available(self, presence):
|
||||||
# TODO Add function to check whether task is already running or not
|
# TODO Add function to check whether task is already running or not
|
||||||
# await task.start_tasks(self, presence)
|
# await task.start_tasks(self, presence)
|
||||||
# NOTE Already done inside the start-task function
|
# NOTE Already done inside the start-task function
|
||||||
jid = presence["from"].bare
|
jid = presence['from'].bare
|
||||||
|
# FIXME TODO Find out what is the source responsible for a couple presences with empty message
|
||||||
|
# NOTE This is a temporary solution
|
||||||
|
await asyncio.sleep(10)
|
||||||
await task.start_tasks_xmpp(self, jid)
|
await task.start_tasks_xmpp(self, jid)
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_unsubscribed(self, presence):
|
async def on_presence_unsubscribed(self, presence):
|
||||||
await state.unsubscribed(self, presence)
|
jid = presence['from'].bare
|
||||||
jid = presence["from"].bare
|
message_body = 'You have been unsubscribed.'
|
||||||
await roster.remove(self, jid)
|
status_message = '🖋️ Subscribe to receive updates'
|
||||||
|
XmppMessage.send(self, jid, message_body, 'chat')
|
||||||
|
XmppPresence.send(self, jid, status_message,
|
||||||
|
presence_type='unsubscribed')
|
||||||
|
await XmppRoster.remove(self, jid)
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_unavailable(self, presence):
|
async def on_presence_unavailable(self, presence):
|
||||||
jid = presence["from"].bare
|
jid = presence['from'].bare
|
||||||
# await task.stop_tasks(self, jid)
|
# await task.stop_tasks(self, jid)
|
||||||
await task.clean_tasks_xmpp(jid)
|
await task.clean_tasks_xmpp(jid)
|
||||||
|
|
||||||
|
@ -299,8 +345,8 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
if message['type'] in ('chat', 'normal'):
|
if message['type'] in ('chat', 'normal'):
|
||||||
jid = message['from'].bare
|
jid = message['from'].bare
|
||||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||||
status_text='Press "help" for manual, or "info" for information.'
|
status_message='Press "help" for manual, or "info" for information.'
|
||||||
status.send(self, jid, status_text)
|
XmppPresence.send(self, jid, status_message)
|
||||||
|
|
||||||
|
|
||||||
async def on_chatstate_gone(self, message):
|
async def on_chatstate_gone(self, message):
|
||||||
|
@ -324,6 +370,25 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# NOTE Failed attempt
|
||||||
|
# Need to use Super or Inheritance or both
|
||||||
|
# self['xep_0050'].add_command(node='settings',
|
||||||
|
# name='Settings',
|
||||||
|
# handler=self._handle_settings)
|
||||||
|
# self['xep_0050'].add_command(node='subscriptions',
|
||||||
|
# name='Subscriptions',
|
||||||
|
# handler=self._handle_subscriptions)
|
||||||
|
|
||||||
|
|
||||||
|
# async def _handle_settings(self, iq, session):
|
||||||
|
# await XmppCommand._handle_settings(self, iq, session)
|
||||||
|
|
||||||
|
|
||||||
|
# async def _handle_subscriptions(self, iq, session):
|
||||||
|
# await XmppCommand._handle_subscriptions(self, iq, session)
|
||||||
|
|
||||||
|
|
||||||
# TODO Move class Service to a separate file
|
# TODO Move class Service to a separate file
|
||||||
# class Service(Slixfeed):
|
# class Service(Slixfeed):
|
||||||
# def __init__(self):
|
# def __init__(self):
|
||||||
|
@ -534,7 +599,8 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
value = True
|
value = True
|
||||||
form.add_field(var='old',
|
form.add_field(var='old',
|
||||||
ftype='boolean',
|
ftype='boolean',
|
||||||
desc='Mark items of newly added subscriptions as read.',
|
desc='Do not mark items of newly added subscriptions '
|
||||||
|
'as read.',
|
||||||
# label='Send only new items',
|
# label='Send only new items',
|
||||||
label='Include old news',
|
label='Include old news',
|
||||||
value=value)
|
value=value)
|
||||||
|
|
|
@ -66,13 +66,16 @@ from slixfeed.xmpp.bookmark import XmppBookmark
|
||||||
import slixfeed.xmpp.connect as connect
|
import slixfeed.xmpp.connect as connect
|
||||||
# NOTE MUC is possible for component
|
# NOTE MUC is possible for component
|
||||||
# import slixfeed.xmpp.muc as muc
|
# import slixfeed.xmpp.muc as muc
|
||||||
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
import slixfeed.xmpp.process as process
|
import slixfeed.xmpp.process as process
|
||||||
import slixfeed.xmpp.profile as profile
|
import slixfeed.xmpp.profile as profile
|
||||||
# import slixfeed.xmpp.roster as roster
|
# import slixfeed.xmpp.roster as roster
|
||||||
# import slixfeed.xmpp.service as service
|
# import slixfeed.xmpp.service as service
|
||||||
import slixfeed.xmpp.state as state
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
import slixfeed.xmpp.status as status
|
from slixfeed.xmpp.utility import XmppUtility
|
||||||
import slixfeed.xmpp.utility as utility
|
from slixmpp.xmlstream import ET
|
||||||
|
# from slixmpp.xmlstream.handler import Callback
|
||||||
|
# from slixmpp.xmlstream.matcher import MatchXPath
|
||||||
|
|
||||||
main_task = []
|
main_task = []
|
||||||
jid_tasker = {}
|
jid_tasker = {}
|
||||||
|
@ -154,13 +157,15 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
# handlers for connection events
|
# handlers for connection events
|
||||||
self.connection_attempts = 0
|
self.connection_attempts = 0
|
||||||
self.max_connection_attempts = 10
|
self.max_connection_attempts = 10
|
||||||
self.add_event_handler("connection_failed", self.on_connection_failed)
|
self.add_event_handler('connection_failed',
|
||||||
self.add_event_handler("session_end", self.on_session_end)
|
self.on_connection_failed)
|
||||||
|
self.add_event_handler('session_end',
|
||||||
|
self.on_session_end)
|
||||||
|
|
||||||
|
|
||||||
# async def on_groupchat_invite(self, message):
|
# async def on_groupchat_invite(self, message):
|
||||||
# logging.warning("on_groupchat_invite")
|
# logging.warning("on_groupchat_invite")
|
||||||
# inviter = message["from"].bare
|
# inviter = message['from'].bare
|
||||||
# muc_jid = message['groupchat_invite']['jid']
|
# muc_jid = message['groupchat_invite']['jid']
|
||||||
# await muc.join(self, inviter, muc_jid)
|
# await muc.join(self, inviter, muc_jid)
|
||||||
# await bookmark.add(self, muc_jid)
|
# await bookmark.add(self, muc_jid)
|
||||||
|
@ -168,27 +173,27 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
|
|
||||||
# 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):
|
||||||
# inviter = message["from"].bare
|
# inviter = message['from'].bare
|
||||||
# muc_jid = message['groupchat_invite']['jid']
|
# muc_jid = message['groupchat_invite']['jid']
|
||||||
# await muc.join(self, inviter, muc_jid)
|
# await muc.join(self, inviter, muc_jid)
|
||||||
# await bookmark.add(self, muc_jid)
|
# await bookmark.add(self, muc_jid)
|
||||||
|
|
||||||
|
|
||||||
async def on_session_end(self, event):
|
async def on_session_end(self, event):
|
||||||
message = "Session has ended."
|
message = 'Session has ended.'
|
||||||
await connect.recover_connection(self, message)
|
await connect.recover_connection(self, message)
|
||||||
|
|
||||||
|
|
||||||
async def on_connection_failed(self, event):
|
async def on_connection_failed(self, event):
|
||||||
message = "Connection has failed. Reason: {}".format(event)
|
message = 'Connection has failed. Reason: {}'.format(event)
|
||||||
await connect.recover_connection(self, message)
|
await connect.recover_connection(self, message)
|
||||||
|
|
||||||
|
|
||||||
async def on_session_start(self, event):
|
async def on_session_start(self, event):
|
||||||
self.send_presence()
|
self.send_presence()
|
||||||
await self["xep_0115"].update_caps()
|
await self['xep_0115'].update_caps()
|
||||||
# await muc.autojoin(self)
|
# await muc.autojoin(self)
|
||||||
profile.set_identity(self, "service")
|
profile.set_identity(self, 'service')
|
||||||
await profile.update(self)
|
await profile.update(self)
|
||||||
task.ping_task(self)
|
task.ping_task(self)
|
||||||
|
|
||||||
|
@ -201,9 +206,9 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
|
|
||||||
async def on_session_resumed(self, event):
|
async def on_session_resumed(self, event):
|
||||||
self.send_presence()
|
self.send_presence()
|
||||||
self["xep_0115"].update_caps()
|
self['xep_0115'].update_caps()
|
||||||
# await muc.autojoin(self)
|
# await muc.autojoin(self)
|
||||||
profile.set_identity(self, "service")
|
profile.set_identity(self, 'service')
|
||||||
|
|
||||||
# Service.commands(self)
|
# Service.commands(self)
|
||||||
# Service.reactions(self)
|
# Service.reactions(self)
|
||||||
|
@ -214,13 +219,21 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
|
|
||||||
# TODO Request for subscription
|
# TODO Request for subscription
|
||||||
async def on_message(self, message):
|
async def on_message(self, message):
|
||||||
# jid = message["from"].bare
|
# jid = message['from'].bare
|
||||||
# if "chat" == await utility.get_chat_type(self, jid):
|
|
||||||
# await roster.add(self, jid)
|
# if "chat" == await XmppUtility.get_chat_type(self, jid):
|
||||||
# await state.request(self, jid)
|
# presence_probe = ET.Element('presence')
|
||||||
|
# presence_probe.attrib['type'] = 'probe'
|
||||||
|
# presence_probe.attrib['to'] = jid
|
||||||
|
# print('presence_probe')
|
||||||
|
# print(presence_probe)
|
||||||
|
# self.send_raw(str(presence_probe))
|
||||||
|
# presence_probe.send()
|
||||||
|
|
||||||
await process.message(self, message)
|
await process.message(self, message)
|
||||||
# chat_type = message["type"]
|
|
||||||
# message_body = message["body"]
|
# chat_type = message['type']
|
||||||
|
# message_body = message['body']
|
||||||
# message_reply = message.reply
|
# message_reply = message.reply
|
||||||
|
|
||||||
|
|
||||||
|
@ -233,31 +246,40 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_subscribe(self, presence):
|
async def on_presence_subscribe(self, presence):
|
||||||
jid = presence["from"].bare
|
jid = presence['from'].bare
|
||||||
# await state.request(self, jid)
|
# XmppPresence.request(self, jid)
|
||||||
self.send_presence_subscription(
|
XmppPresence.subscribe(self, jid)
|
||||||
pto=jid,
|
|
||||||
pfrom=self.boundjid.bare,
|
|
||||||
ptype="subscribe",
|
|
||||||
pnick=self.alias
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_subscribed(self, presence):
|
async def on_presence_subscribed(self, presence):
|
||||||
jid = presence["from"].bare
|
jid = presence['from'].bare
|
||||||
process.greet(self, jid)
|
if await XmppUtility.get_chat_type(self, jid) == 'chat':
|
||||||
|
message_subject = 'RSS News Bot'
|
||||||
|
message_body = ('Greetings!\n'
|
||||||
|
'I am {}, the news anchor.\n'
|
||||||
|
'My job is to bring you the latest '
|
||||||
|
'news from sources you provide me with.\n'
|
||||||
|
'You may always reach me via xmpp:{}?message'
|
||||||
|
.format(self.alias, self.boundjid.bare))
|
||||||
|
XmppMessage.send_headline(self, jid, message_subject, message_body,
|
||||||
|
'chat')
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_available(self, presence):
|
async def on_presence_available(self, presence):
|
||||||
# TODO Add function to check whether task is already running or not
|
# TODO Add function to check whether task is already running or not
|
||||||
# await task.start_tasks(self, presence)
|
# await task.start_tasks(self, presence)
|
||||||
# NOTE Already done inside the start-task function
|
# NOTE Already done inside the start-task function
|
||||||
jid = presence["from"].bare
|
jid = presence['from'].bare
|
||||||
await task.start_tasks_xmpp(self, jid)
|
await task.start_tasks_xmpp(self, jid)
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_unsubscribed(self, presence):
|
async def on_presence_unsubscribed(self, presence):
|
||||||
await state.unsubscribed(self, presence)
|
jid = presence['from'].bare
|
||||||
|
message = 'You have been unsubscribed.'
|
||||||
|
status_message = '🖋️ Subscribe to receive updates'
|
||||||
|
chat_type = await XmppUtility.get_chat_type(self, jid)
|
||||||
|
XmppMessage.send(self, jid, message, chat_type)
|
||||||
|
XmppPresence.send(self, jid, status_message, chat_type)
|
||||||
|
|
||||||
|
|
||||||
async def on_presence_unavailable(self, presence):
|
async def on_presence_unavailable(self, presence):
|
||||||
|
@ -294,8 +316,9 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
if message['type'] in ('chat', 'normal'):
|
if message['type'] in ('chat', 'normal'):
|
||||||
jid = message['from'].bare
|
jid = message['from'].bare
|
||||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||||
status_text='Press "help" for manual, or "info" for information.'
|
status_message='Press "help" for manual, or "info" for information.'
|
||||||
status.send(self, jid, status_text)
|
chat_type = await XmppUtility.get_chat_type(self, jid)
|
||||||
|
XmppPresence.send(self, jid, status_message, chat_type)
|
||||||
|
|
||||||
|
|
||||||
async def on_chatstate_gone(self, message):
|
async def on_chatstate_gone(self, message):
|
||||||
|
|
|
@ -21,63 +21,65 @@ from time import sleep
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
async def ping(self, jid=None):
|
class XmppConnect:
|
||||||
"""
|
|
||||||
Check for ping and disconnect if no ping has been received.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
jid : str, optional
|
|
||||||
Jabber ID. The default is None.
|
|
||||||
|
|
||||||
Returns
|
async def ping(self, jid=None):
|
||||||
-------
|
"""
|
||||||
None.
|
Check for ping and disconnect if no ping has been received.
|
||||||
|
|
||||||
"""
|
Parameters
|
||||||
if not jid:
|
----------
|
||||||
jid = self.boundjid.bare
|
jid : str, optional
|
||||||
while True:
|
Jabber ID. The default is None.
|
||||||
rtt = None
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
None.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not jid:
|
||||||
|
jid = self.boundjid.bare
|
||||||
|
while True:
|
||||||
|
rtt = None
|
||||||
|
try:
|
||||||
|
rtt = await self['xep_0199'].ping(jid, timeout=10)
|
||||||
|
logging.info("Success! RTT: %s", rtt)
|
||||||
|
except IqError as e:
|
||||||
|
logging.info("Error pinging %s: %s",
|
||||||
|
jid,
|
||||||
|
e.iq['error']['condition'])
|
||||||
|
except IqTimeout:
|
||||||
|
logging.info("No response from %s", jid)
|
||||||
|
if not rtt:
|
||||||
|
self.disconnect()
|
||||||
|
await asyncio.sleep(60 * 1)
|
||||||
|
|
||||||
|
|
||||||
|
async def recover(self, message):
|
||||||
|
logging.warning(message)
|
||||||
|
print(current_time(), message, "Attempting to reconnect.")
|
||||||
|
self.connection_attempts += 1
|
||||||
|
# if self.connection_attempts <= self.max_connection_attempts:
|
||||||
|
# self.reconnect(wait=5.0) # wait a bit before attempting to reconnect
|
||||||
|
# else:
|
||||||
|
# print(current_time(),"Maximum connection attempts exceeded.")
|
||||||
|
# logging.error("Maximum connection attempts exceeded.")
|
||||||
|
print(current_time(), "Attempt number", self.connection_attempts)
|
||||||
|
seconds = (get_value("accounts", "XMPP", "reconnect_timeout")) or 30
|
||||||
|
seconds = int(seconds)
|
||||||
|
print(current_time(), "Next attempt within", seconds, "seconds")
|
||||||
|
# NOTE asyncio.sleep doesn't interval as expected
|
||||||
|
# await asyncio.sleep(seconds)
|
||||||
|
sleep(seconds)
|
||||||
|
self.reconnect(wait=5.0)
|
||||||
|
|
||||||
|
|
||||||
|
async def inspect(self):
|
||||||
|
print('Disconnected\n'
|
||||||
|
'Reconnecting...')
|
||||||
try:
|
try:
|
||||||
rtt = await self['xep_0199'].ping(jid, timeout=10)
|
self.reconnect
|
||||||
logging.info("Success! RTT: %s", rtt)
|
except:
|
||||||
except IqError as e:
|
|
||||||
logging.info("Error pinging %s: %s",
|
|
||||||
jid,
|
|
||||||
e.iq['error']['condition'])
|
|
||||||
except IqTimeout:
|
|
||||||
logging.info("No response from %s", jid)
|
|
||||||
if not rtt:
|
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
await asyncio.sleep(60 * 1)
|
print('Problem reconnecting')
|
||||||
|
|
||||||
|
|
||||||
async def recover_connection(self, message):
|
|
||||||
logging.warning(message)
|
|
||||||
print(current_time(), message, "Attempting to reconnect.")
|
|
||||||
self.connection_attempts += 1
|
|
||||||
# if self.connection_attempts <= self.max_connection_attempts:
|
|
||||||
# self.reconnect(wait=5.0) # wait a bit before attempting to reconnect
|
|
||||||
# else:
|
|
||||||
# print(current_time(),"Maximum connection attempts exceeded.")
|
|
||||||
# logging.error("Maximum connection attempts exceeded.")
|
|
||||||
print(current_time(), "Attempt number", self.connection_attempts)
|
|
||||||
seconds = (get_value(
|
|
||||||
"accounts", "XMPP", "reconnect_timeout")) or 30
|
|
||||||
seconds = int(seconds)
|
|
||||||
print(current_time(), "Next attempt within", seconds, "seconds")
|
|
||||||
# NOTE asyncio.sleep doesn't interval as expected
|
|
||||||
# await asyncio.sleep(seconds)
|
|
||||||
sleep(seconds)
|
|
||||||
self.reconnect(wait=5.0)
|
|
||||||
|
|
||||||
|
|
||||||
async def inspect_connection(self, event):
|
|
||||||
print("Disconnected\nReconnecting...")
|
|
||||||
print(event)
|
|
||||||
try:
|
|
||||||
self.reconnect
|
|
||||||
except:
|
|
||||||
self.disconnect()
|
|
||||||
print("Problem reconnecting")
|
|
||||||
|
|
|
@ -1,37 +1,77 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
# import slixfeed.action as action
|
||||||
|
import slixfeed.config as config
|
||||||
|
from slixfeed.dt import current_time, timestamp
|
||||||
|
import slixfeed.fetch as fetch
|
||||||
|
import slixfeed.sqlite as sqlite
|
||||||
|
import slixfeed.task as task
|
||||||
|
import slixfeed.url as uri
|
||||||
|
from slixfeed.xmpp.bookmark import XmppBookmark
|
||||||
|
# from slixfeed.xmpp.muc import XmppGroupchat
|
||||||
|
# from slixfeed.xmpp.message import XmppMessage
|
||||||
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
|
from slixfeed.xmpp.upload import XmppUpload
|
||||||
from slixfeed.xmpp.utility import get_chat_type
|
from slixfeed.xmpp.utility import get_chat_type
|
||||||
|
import time
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
|
||||||
|
See XEP-0367: Message Attaching
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
class XmppMessage:
|
class XmppMessage:
|
||||||
|
|
||||||
async def send(self, jid, message, chat_type=None):
|
|
||||||
if not chat_type:
|
# def process():
|
||||||
chat_type = await get_chat_type(self, jid)
|
|
||||||
self.send_message(
|
|
||||||
mto=jid,
|
|
||||||
mfrom=self.boundjid.bare,
|
|
||||||
mbody=message,
|
|
||||||
mtype=chat_type
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def send_oob(self, jid, url):
|
def send(self, jid, message_body, chat_type):
|
||||||
chat_type = await get_chat_type(self, jid)
|
self.send_message(mto=jid,
|
||||||
|
mfrom=self.boundjid.bare,
|
||||||
|
mbody=message_body,
|
||||||
|
mtype=chat_type)
|
||||||
|
|
||||||
|
|
||||||
|
def send_headline(self, jid, message_subject, message_body, chat_type):
|
||||||
|
self.send_message(mto=jid,
|
||||||
|
mfrom=self.boundjid.bare,
|
||||||
|
# mtype='headline',
|
||||||
|
msubject=message_subject,
|
||||||
|
mbody=message_body,
|
||||||
|
mtype=chat_type,
|
||||||
|
mnick=self.alias)
|
||||||
|
|
||||||
|
|
||||||
|
def send_oob(self, jid, url, chat_type):
|
||||||
html = (
|
html = (
|
||||||
f'<body xmlns="http://www.w3.org/1999/xhtml">'
|
f'<body xmlns="http://www.w3.org/1999/xhtml">'
|
||||||
f'<a href="{url}">{url}</a></body>')
|
f'<a href="{url}">{url}</a></body>')
|
||||||
message = self.make_message(
|
message = self.make_message(mto=jid,
|
||||||
mto=jid,
|
mfrom=self.boundjid.bare,
|
||||||
mfrom=self.boundjid.bare,
|
mbody=url,
|
||||||
mbody=url,
|
mhtml=html,
|
||||||
mhtml=html,
|
mtype=chat_type)
|
||||||
mtype=chat_type
|
|
||||||
)
|
|
||||||
message['oob']['url'] = url
|
message['oob']['url'] = url
|
||||||
message.send()
|
message.send()
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME Solve this function
|
||||||
|
def send_oob_reply_message(message, url, response):
|
||||||
|
reply = message.reply(response)
|
||||||
|
reply['oob']['url'] = url
|
||||||
|
reply.send()
|
||||||
|
|
||||||
|
|
||||||
|
# def send_reply(self, message, message_body):
|
||||||
|
# message.reply(message_body).send()
|
||||||
|
|
||||||
|
|
||||||
def send_reply(self, message, response):
|
def send_reply(self, message, response):
|
||||||
message.reply(response).send()
|
message.reply(response).send()
|
||||||
|
|
|
@ -17,102 +17,90 @@ FIXME
|
||||||
|
|
||||||
"""
|
"""
|
||||||
import logging
|
import logging
|
||||||
import slixfeed.xmpp.process as process
|
|
||||||
from slixfeed.dt import current_time
|
from slixfeed.dt import current_time
|
||||||
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
|
|
||||||
# async def accept_muc_invite(self, message, ctr=None):
|
class XmppGroupchat:
|
||||||
# # if isinstance(message, str):
|
|
||||||
# if not ctr:
|
# async def accept_muc_invite(self, message, ctr=None):
|
||||||
# ctr = message["from"].bare
|
# # if isinstance(message, str):
|
||||||
# jid = message['groupchat_invite']['jid']
|
# if not ctr:
|
||||||
# else:
|
# ctr = message["from"].bare
|
||||||
# jid = message
|
# jid = message['groupchat_invite']['jid']
|
||||||
async def accept_invitation(self, message):
|
# else:
|
||||||
# operator muc_chat
|
# jid = message
|
||||||
inviter = message["from"].bare
|
async def accept_invitation(self, message):
|
||||||
muc_jid = message['groupchat_invite']['jid']
|
# operator muc_chat
|
||||||
await join(self, inviter, muc_jid)
|
inviter = message["from"].bare
|
||||||
|
muc_jid = message['groupchat_invite']['jid']
|
||||||
|
await self.join(self, inviter, muc_jid)
|
||||||
|
|
||||||
|
|
||||||
async def autojoin(self):
|
async def autojoin(self):
|
||||||
result = await self.plugin['xep_0048'].get_bookmarks()
|
result = await self.plugin['xep_0048'].get_bookmarks()
|
||||||
bookmarks = result["private"]["bookmarks"]
|
bookmarks = result["private"]["bookmarks"]
|
||||||
conferences = bookmarks["conferences"]
|
conferences = bookmarks["conferences"]
|
||||||
for conference in conferences:
|
for conference in conferences:
|
||||||
if conference["autojoin"]:
|
if conference["autojoin"]:
|
||||||
muc_jid = conference["jid"]
|
muc_jid = conference["jid"]
|
||||||
logging.info(
|
self.plugin['xep_0045'].join_muc(muc_jid,
|
||||||
'Autojoin groupchat\n'
|
conference["nick"],
|
||||||
'Name : {}\n'
|
# If a room password is needed, use:
|
||||||
'JID : {}\n'
|
# password=the_room_password,
|
||||||
'Alias : {}\n'
|
)
|
||||||
.format(
|
logging.info('Autojoin groupchat\n'
|
||||||
conference["name"],
|
'Name : {}\n'
|
||||||
muc_jid,
|
'JID : {}\n'
|
||||||
conference["nick"]
|
'Alias : {}\n'
|
||||||
))
|
.format(conference["name"],
|
||||||
self.plugin['xep_0045'].join_muc(
|
muc_jid,
|
||||||
muc_jid,
|
conference["nick"]))
|
||||||
conference["nick"],
|
|
||||||
# If a room password is needed, use:
|
|
||||||
# password=the_room_password,
|
|
||||||
)
|
|
||||||
|
|
||||||
async def join(self, inviter, muc_jid):
|
|
||||||
# token = await initdb(
|
|
||||||
# muc_jid,
|
|
||||||
# get_settings_value,
|
|
||||||
# "token"
|
|
||||||
# )
|
|
||||||
# if token != "accepted":
|
|
||||||
# token = randrange(10000, 99999)
|
|
||||||
# await initdb(
|
|
||||||
# muc_jid,
|
|
||||||
# update_settings_value,
|
|
||||||
# ["token", token]
|
|
||||||
# )
|
|
||||||
# self.send_message(
|
|
||||||
# mto=inviter,
|
|
||||||
# mfrom=self.boundjid.bare,
|
|
||||||
# mbody=(
|
|
||||||
# "Send activation token {} to groupchat xmpp:{}?join."
|
|
||||||
# ).format(token, muc_jid)
|
|
||||||
# )
|
|
||||||
logging.info(
|
|
||||||
'Joining groupchat\n'
|
|
||||||
'JID : {}\n'
|
|
||||||
'Inviter : {}\n'
|
|
||||||
.format(
|
|
||||||
muc_jid,
|
|
||||||
inviter
|
|
||||||
))
|
|
||||||
self.plugin['xep_0045'].join_muc(
|
|
||||||
muc_jid,
|
|
||||||
self.alias,
|
|
||||||
# If a room password is needed, use:
|
|
||||||
# password=the_room_password,
|
|
||||||
)
|
|
||||||
process.greet(self, muc_jid, chat_type="groupchat")
|
|
||||||
|
|
||||||
|
|
||||||
async def leave(self, muc_jid):
|
async def join(self, inviter, muc_jid):
|
||||||
messages = [
|
# token = await initdb(
|
||||||
"Whenever you need an RSS service again, "
|
# muc_jid,
|
||||||
"please don’t hesitate to contact me.",
|
# get_settings_value,
|
||||||
"My personal contact is xmpp:{}?message".format(self.boundjid.bare),
|
# "token"
|
||||||
"Farewell, and take care."
|
# )
|
||||||
]
|
# if token != "accepted":
|
||||||
for message in messages:
|
# token = randrange(10000, 99999)
|
||||||
self.send_message(
|
# await initdb(
|
||||||
mto=muc_jid,
|
# muc_jid,
|
||||||
mfrom=self.boundjid.bare,
|
# update_settings_value,
|
||||||
mbody=message,
|
# ["token", token]
|
||||||
mtype="groupchat"
|
# )
|
||||||
)
|
# self.send_message(
|
||||||
self.plugin['xep_0045'].leave_muc(
|
# mto=inviter,
|
||||||
muc_jid,
|
# mfrom=self.boundjid.bare,
|
||||||
self.alias,
|
# mbody=(
|
||||||
"Goodbye!",
|
# "Send activation token {} to groupchat xmpp:{}?join."
|
||||||
self.boundjid.bare
|
# ).format(token, muc_jid)
|
||||||
)
|
# )
|
||||||
|
logging.info('Joining groupchat\n'
|
||||||
|
'JID : {}\n'
|
||||||
|
'Inviter : {}\n'
|
||||||
|
.format(muc_jid, inviter))
|
||||||
|
self.plugin['xep_0045'].join_muc(muc_jid,
|
||||||
|
self.alias,
|
||||||
|
# If a room password is needed, use:
|
||||||
|
# password=the_room_password,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def leave(self, muc_jid):
|
||||||
|
messages = [
|
||||||
|
"Whenever you need an RSS service again, "
|
||||||
|
"please don’t hesitate to contact me.",
|
||||||
|
"My JID is xmpp:{}?message".format(self.boundjid.bare),
|
||||||
|
"Farewell."
|
||||||
|
]
|
||||||
|
for message in messages:
|
||||||
|
self.send_message(mto=muc_jid,
|
||||||
|
mfrom=self.boundjid.bare,
|
||||||
|
mbody=message,
|
||||||
|
mtype='groupchat')
|
||||||
|
self.plugin['xep_0045'].leave_muc(muc_jid,
|
||||||
|
self.alias,
|
||||||
|
'Goodbye!',
|
||||||
|
self.boundjid.bare)
|
||||||
|
|
37
slixfeed/xmpp/presence.py
Normal file
37
slixfeed/xmpp/presence.py
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
NOTE
|
||||||
|
|
||||||
|
Accept symbols 🉑️ 👍️ ✍
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
class XmppPresence:
|
||||||
|
|
||||||
|
|
||||||
|
def send(self, jid, status_message, presence_type=None, status_type=None):
|
||||||
|
self.send_presence(pto=jid,
|
||||||
|
pfrom=self.boundjid.bare,
|
||||||
|
pshow=status_type,
|
||||||
|
pstatus=status_message,
|
||||||
|
ptype=presence_type)
|
||||||
|
|
||||||
|
|
||||||
|
def subscribe(self, jid):
|
||||||
|
self.send_presence_subscription(pto=jid,
|
||||||
|
pfrom=self.boundjid.bare,
|
||||||
|
ptype='subscribe',
|
||||||
|
pnick=self.alias)
|
||||||
|
|
||||||
|
|
||||||
|
def remove(self):
|
||||||
|
"""
|
||||||
|
Remove subscription from JID that do not (stopped) share presence.
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
None.
|
||||||
|
"""
|
|
@ -9,7 +9,7 @@ TODO
|
||||||
Slixfeed: Do you still want to add this URL to subscription list?
|
Slixfeed: Do you still want to add this URL to subscription list?
|
||||||
See: case _ if message_lowercase.startswith("add"):
|
See: case _ if message_lowercase.startswith("add"):
|
||||||
|
|
||||||
2) If subscription is inadequate (see state.request), send a message that says so.
|
2) If subscription is inadequate (see XmppPresence.request), send a message that says so.
|
||||||
|
|
||||||
elif not self.client_roster[jid]["to"]:
|
elif not self.client_roster[jid]["to"]:
|
||||||
breakpoint()
|
breakpoint()
|
||||||
|
@ -28,9 +28,10 @@ import slixfeed.sqlite as sqlite
|
||||||
import slixfeed.task as task
|
import slixfeed.task as task
|
||||||
import slixfeed.url as uri
|
import slixfeed.url as uri
|
||||||
from slixfeed.xmpp.bookmark import XmppBookmark
|
from slixfeed.xmpp.bookmark import XmppBookmark
|
||||||
import slixfeed.xmpp.muc as groupchat
|
from slixfeed.xmpp.muc import XmppGroupchat
|
||||||
from slixfeed.xmpp.status import XmppStatus
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
import slixfeed.xmpp.upload as upload
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
|
from slixfeed.xmpp.upload import XmppUpload
|
||||||
from slixfeed.xmpp.utility import get_chat_type
|
from slixfeed.xmpp.utility import get_chat_type
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -88,7 +89,8 @@ async def message(self, message):
|
||||||
await task.clean_tasks_xmpp(jid, ['status'])
|
await task.clean_tasks_xmpp(jid, ['status'])
|
||||||
status_type = 'dnd'
|
status_type = 'dnd'
|
||||||
status_message = '📥️ Procesing request to import feeds...'
|
status_message = '📥️ Procesing request to import feeds...'
|
||||||
await XmppStatus.send(self, jid, status_message, status_type)
|
XmppPresence.send(self, jid, status_message,
|
||||||
|
status_type=status_type)
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
count = await action.import_opml(db_file, url)
|
count = await action.import_opml(db_file, url)
|
||||||
if count:
|
if count:
|
||||||
|
@ -97,7 +99,7 @@ async def message(self, message):
|
||||||
response = 'OPML file was not imported.'
|
response = 'OPML file was not imported.'
|
||||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,7 +192,7 @@ async def message(self, message):
|
||||||
# 'This action is restricted. '
|
# 'This action is restricted. '
|
||||||
# 'Type: breakpoint.'
|
# 'Type: breakpoint.'
|
||||||
# )
|
# )
|
||||||
# send_reply_message(self, message, response)
|
# XmppMessage.send_reply(self, message, response)
|
||||||
case 'help':
|
case 'help':
|
||||||
command_list = ' '.join(action.manual('commands.toml'))
|
command_list = ' '.join(action.manual('commands.toml'))
|
||||||
response = ('Available command keys:\n'
|
response = ('Available command keys:\n'
|
||||||
|
@ -198,7 +200,7 @@ async def message(self, message):
|
||||||
'Usage: `help <key>`'
|
'Usage: `help <key>`'
|
||||||
.format(command_list))
|
.format(command_list))
|
||||||
print(response)
|
print(response)
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('help'):
|
case _ if message_lowercase.startswith('help'):
|
||||||
command = message_text[5:]
|
command = message_text[5:]
|
||||||
command = command.split(' ')
|
command = command.split(' ')
|
||||||
|
@ -228,14 +230,14 @@ async def message(self, message):
|
||||||
else:
|
else:
|
||||||
response = ('Invalid. Enter command key '
|
response = ('Invalid. Enter command key '
|
||||||
'or command key & name')
|
'or command key & name')
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case 'info':
|
case 'info':
|
||||||
command_list = ' '.join(action.manual('information.toml'))
|
command_list = ' '.join(action.manual('information.toml'))
|
||||||
response = ('Available command options:\n'
|
response = ('Available command options:\n'
|
||||||
'```\n{}\n```\n'
|
'```\n{}\n```\n'
|
||||||
'Usage: `info <option>`'
|
'Usage: `info <option>`'
|
||||||
.format(command_list))
|
.format(command_list))
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('info'):
|
case _ if message_lowercase.startswith('info'):
|
||||||
command = message_text[5:]
|
command = message_text[5:]
|
||||||
command_list = action.manual('information.toml', command)
|
command_list = action.manual('information.toml', command)
|
||||||
|
@ -245,7 +247,7 @@ async def message(self, message):
|
||||||
else:
|
else:
|
||||||
response = ('KeyError for {}'
|
response = ('KeyError for {}'
|
||||||
.format(command))
|
.format(command))
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase in ['greetings', 'hallo', 'hello',
|
case _ if message_lowercase in ['greetings', 'hallo', 'hello',
|
||||||
'hey', 'hi', 'hola', 'holla',
|
'hey', 'hi', 'hola', 'holla',
|
||||||
'hollo']:
|
'hollo']:
|
||||||
|
@ -253,7 +255,7 @@ async def message(self, message):
|
||||||
'I am an RSS News Bot.\n'
|
'I am an RSS News Bot.\n'
|
||||||
'Send "help" for further instructions.\n'
|
'Send "help" for further instructions.\n'
|
||||||
.format(self.alias))
|
.format(self.alias))
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
|
|
||||||
# case _ if message_lowercase.startswith('activate'):
|
# case _ if message_lowercase.startswith('activate'):
|
||||||
# if message['type'] == 'groupchat':
|
# if message['type'] == 'groupchat':
|
||||||
|
@ -315,7 +317,7 @@ async def message(self, message):
|
||||||
.format(url, name, ix))
|
.format(url, name, ix))
|
||||||
else:
|
else:
|
||||||
response = 'Missing URL.'
|
response = 'Missing URL.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('allow +'):
|
case _ if message_lowercase.startswith('allow +'):
|
||||||
key = 'filter-' + message_text[:5]
|
key = 'filter-' + message_text[:5]
|
||||||
val = message_text[7:]
|
val = message_text[7:]
|
||||||
|
@ -333,7 +335,7 @@ async def message(self, message):
|
||||||
.format(val))
|
.format(val))
|
||||||
else:
|
else:
|
||||||
response = 'Missing keywords.'
|
response = 'Missing keywords.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('allow -'):
|
case _ if message_lowercase.startswith('allow -'):
|
||||||
key = 'filter-' + message_text[:5]
|
key = 'filter-' + message_text[:5]
|
||||||
val = message_text[7:]
|
val = message_text[7:]
|
||||||
|
@ -351,7 +353,7 @@ async def message(self, message):
|
||||||
.format(val))
|
.format(val))
|
||||||
else:
|
else:
|
||||||
response = 'Missing keywords.'
|
response = 'Missing keywords.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('archive'):
|
case _ if message_lowercase.startswith('archive'):
|
||||||
key = message_text[:7]
|
key = message_text[:7]
|
||||||
val = message_text[8:]
|
val = message_text[8:]
|
||||||
|
@ -375,7 +377,7 @@ async def message(self, message):
|
||||||
response = 'Enter a numeric value only.'
|
response = 'Enter a numeric value only.'
|
||||||
else:
|
else:
|
||||||
response = 'Missing value.'
|
response = 'Missing value.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('bookmark -'):
|
case _ if message_lowercase.startswith('bookmark -'):
|
||||||
if jid == config.get_value('accounts', 'XMPP', 'operator'):
|
if jid == config.get_value('accounts', 'XMPP', 'operator'):
|
||||||
muc_jid = message_text[11:]
|
muc_jid = message_text[11:]
|
||||||
|
@ -386,14 +388,14 @@ async def message(self, message):
|
||||||
else:
|
else:
|
||||||
response = ('This action is restricted. '
|
response = ('This action is restricted. '
|
||||||
'Type: removing bookmarks.')
|
'Type: removing bookmarks.')
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case 'bookmarks':
|
case 'bookmarks':
|
||||||
if jid == config.get_value('accounts', 'XMPP', 'operator'):
|
if jid == config.get_value('accounts', 'XMPP', 'operator'):
|
||||||
response = await action.list_bookmarks(self)
|
response = await action.list_bookmarks(self)
|
||||||
else:
|
else:
|
||||||
response = ('This action is restricted. '
|
response = ('This action is restricted. '
|
||||||
'Type: viewing bookmarks.')
|
'Type: viewing bookmarks.')
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('deny +'):
|
case _ if message_lowercase.startswith('deny +'):
|
||||||
key = 'filter-' + message_text[:4]
|
key = 'filter-' + message_text[:4]
|
||||||
val = message_text[6:]
|
val = message_text[6:]
|
||||||
|
@ -411,7 +413,7 @@ async def message(self, message):
|
||||||
.format(val))
|
.format(val))
|
||||||
else:
|
else:
|
||||||
response = 'Missing keywords.'
|
response = 'Missing keywords.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('deny -'):
|
case _ if message_lowercase.startswith('deny -'):
|
||||||
key = 'filter-' + message_text[:4]
|
key = 'filter-' + message_text[:4]
|
||||||
val = message_text[6:]
|
val = message_text[6:]
|
||||||
|
@ -429,7 +431,7 @@ async def message(self, message):
|
||||||
.format(val))
|
.format(val))
|
||||||
else:
|
else:
|
||||||
response = 'Missing keywords.'
|
response = 'Missing keywords.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('export'):
|
case _ if message_lowercase.startswith('export'):
|
||||||
ex = message_text[7:]
|
ex = message_text[7:]
|
||||||
if ex in ('opml', 'html', 'md', 'xbel'):
|
if ex in ('opml', 'html', 'md', 'xbel'):
|
||||||
|
@ -437,8 +439,8 @@ async def message(self, message):
|
||||||
status_message = ('📤️ Procesing request to '
|
status_message = ('📤️ Procesing request to '
|
||||||
'export feeds into {}...'
|
'export feeds into {}...'
|
||||||
.format(ex))
|
.format(ex))
|
||||||
await XmppStatus.send(self, jid, status_message,
|
XmppPresence.send(self, jid, status_message,
|
||||||
status_type)
|
status_type=status_type)
|
||||||
cache_dir = config.get_default_cache_directory()
|
cache_dir = config.get_default_cache_directory()
|
||||||
if not os.path.isdir(cache_dir):
|
if not os.path.isdir(cache_dir):
|
||||||
os.mkdir(cache_dir)
|
os.mkdir(cache_dir)
|
||||||
|
@ -457,105 +459,33 @@ async def message(self, message):
|
||||||
action.export_to_opml(jid, filename, results)
|
action.export_to_opml(jid, filename, results)
|
||||||
case 'xbel':
|
case 'xbel':
|
||||||
response = 'Not yet implemented.'
|
response = 'Not yet implemented.'
|
||||||
url = await upload.start(self, jid, filename)
|
url = await XmppUpload.start(self, jid, filename)
|
||||||
# response = (
|
# response = (
|
||||||
# 'Feeds exported successfully to {}.\n{}'
|
# 'Feeds exported successfully to {}.\n{}'
|
||||||
# ).format(ex, url)
|
# ).format(ex, url)
|
||||||
# send_oob_reply_message(message, url, response)
|
# XmppMessage.send_oob_reply_message(message, url, response)
|
||||||
await send_oob_message(self, jid, url)
|
chat_type = await get_chat_type(self, jid)
|
||||||
|
XmppMessage.send_oob(self, jid, url, chat_type)
|
||||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||||
else:
|
else:
|
||||||
response = ('Unsupported filetype.\n'
|
response = ('Unsupported filetype.\n'
|
||||||
'Try: html, md, opml, or xbel')
|
'Try: html, md, opml, or xbel')
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if (message_lowercase.startswith('gemini:') or
|
case _ if (message_lowercase.startswith('gemini:') or
|
||||||
message_lowercase.startswith('gopher:')):
|
message_lowercase.startswith('gopher:')):
|
||||||
response = 'Gemini and Gopher are not supported yet.'
|
response = 'Gemini and Gopher are not supported yet.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
# TODO xHTML, HTMLZ, Markdown, MHTML, PDF, TXT
|
# TODO xHTML, HTMLZ, MHTML
|
||||||
case _ if (message_lowercase.startswith('get')):
|
case _ if (message_lowercase.startswith('page')):
|
||||||
message_text = message_text[4:]
|
message_text = message_text[5:]
|
||||||
ix_url = message_text.split(' ')[0]
|
ix_url = message_text.split(' ')[0]
|
||||||
ext = ' '.join(message_text.split(' ')[1:])
|
await action.download_document(self, message, jid, jid_file,
|
||||||
ext = ext if ext else 'pdf'
|
message_text, ix_url, False)
|
||||||
url = None
|
case _ if (message_lowercase.startswith('content')):
|
||||||
error = None
|
message_text = message_text[8:]
|
||||||
if ext in ('epub', 'html', 'markdown',
|
ix_url = message_text.split(' ')[0]
|
||||||
'md', 'pdf', 'text', 'txt'):
|
await action.download_document(self, message, jid, jid_file,
|
||||||
match ext:
|
message_text, ix_url, True)
|
||||||
case 'markdown':
|
|
||||||
ext = 'md'
|
|
||||||
case 'text':
|
|
||||||
ext = 'txt'
|
|
||||||
status_type = 'dnd'
|
|
||||||
status_message = ('📃️ Procesing request to '
|
|
||||||
'produce {} document...'
|
|
||||||
.format(ext.upper()))
|
|
||||||
await XmppStatus.send(self, jid, status_message,
|
|
||||||
status_type)
|
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
|
||||||
cache_dir = config.get_default_cache_directory()
|
|
||||||
if ix_url:
|
|
||||||
if not os.path.isdir(cache_dir):
|
|
||||||
os.mkdir(cache_dir)
|
|
||||||
if not os.path.isdir(cache_dir + '/readability'):
|
|
||||||
os.mkdir(cache_dir + '/readability')
|
|
||||||
try:
|
|
||||||
ix = int(ix_url)
|
|
||||||
try:
|
|
||||||
url = sqlite.get_entry_url(db_file, ix)
|
|
||||||
except:
|
|
||||||
response = 'No entry with index {}'.format(ix)
|
|
||||||
except:
|
|
||||||
url = ix_url
|
|
||||||
if url:
|
|
||||||
logging.info('Original URL: {}'
|
|
||||||
.format(url))
|
|
||||||
url = uri.remove_tracking_parameters(url)
|
|
||||||
logging.info('Processed URL (tracker removal): {}'
|
|
||||||
.format(url))
|
|
||||||
url = (uri.replace_hostname(url, 'link')) or url
|
|
||||||
logging.info('Processed URL (replace hostname): {}'
|
|
||||||
.format(url))
|
|
||||||
result = await fetch.http(url)
|
|
||||||
data = result[0]
|
|
||||||
code = result[1]
|
|
||||||
if data:
|
|
||||||
title = action.get_document_title(data)
|
|
||||||
title = title.strip().lower()
|
|
||||||
for i in (' ', '-'):
|
|
||||||
title = title.replace(i, '_')
|
|
||||||
for i in ('?', '"', '\'', '!'):
|
|
||||||
title = title.replace(i, '')
|
|
||||||
filename = os.path.join(
|
|
||||||
cache_dir, 'readability',
|
|
||||||
title + '_' + timestamp() + '.' + ext)
|
|
||||||
error = action.generate_document(data, url,
|
|
||||||
ext, filename)
|
|
||||||
if error:
|
|
||||||
response = ('> {}\n'
|
|
||||||
'Failed to export {}. '
|
|
||||||
'Reason: {}'
|
|
||||||
.format(url, ext.upper(),
|
|
||||||
error))
|
|
||||||
else:
|
|
||||||
url = await upload.start(self, jid,
|
|
||||||
filename)
|
|
||||||
await send_oob_message(self, jid, url)
|
|
||||||
else:
|
|
||||||
response = ('> {}\n'
|
|
||||||
'Failed to fetch URL. Reason: {}'
|
|
||||||
.format(url, code))
|
|
||||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
|
||||||
else:
|
|
||||||
response = 'Missing entry index number.'
|
|
||||||
else:
|
|
||||||
response = ('Unsupported filetype.\n'
|
|
||||||
'Try: epub, html, md (markdown), '
|
|
||||||
'pdf, or txt (text)')
|
|
||||||
if response:
|
|
||||||
logging.warning('Error for URL {}: {}'.format(url, error))
|
|
||||||
send_reply_message(self, message, response)
|
|
||||||
# case _ if (message_lowercase.startswith('http')) and(
|
# case _ if (message_lowercase.startswith('http')) and(
|
||||||
# message_lowercase.endswith('.opml')):
|
# message_lowercase.endswith('.opml')):
|
||||||
# url = message_text
|
# url = message_text
|
||||||
|
@ -565,8 +495,8 @@ async def message(self, message):
|
||||||
# status_message = (
|
# status_message = (
|
||||||
# '📥️ Procesing request to import feeds...'
|
# '📥️ Procesing request to import feeds...'
|
||||||
# )
|
# )
|
||||||
# await XmppStatus.send(
|
# XmppPresence.send(
|
||||||
# self, jid, status_message, status_type)
|
# self, jid, status_message, status_type=status_type)
|
||||||
# db_file = config.get_pathname_to_database(jid_file)
|
# db_file = config.get_pathname_to_database(jid_file)
|
||||||
# count = await action.import_opml(db_file, url)
|
# count = await action.import_opml(db_file, url)
|
||||||
# if count:
|
# if count:
|
||||||
|
@ -581,7 +511,7 @@ async def message(self, message):
|
||||||
# jid, ['status'])
|
# jid, ['status'])
|
||||||
# await task.start_tasks_xmpp(
|
# await task.start_tasks_xmpp(
|
||||||
# self, jid, ['status'])
|
# self, jid, ['status'])
|
||||||
# send_reply_message(self, message, response)
|
# XmppMessage.send_reply(self, message, response)
|
||||||
case _ if (message_lowercase.startswith('http') or
|
case _ if (message_lowercase.startswith('http') or
|
||||||
message_lowercase.startswith('feed:')):
|
message_lowercase.startswith('feed:')):
|
||||||
url = message_text
|
url = message_text
|
||||||
|
@ -590,7 +520,8 @@ async def message(self, message):
|
||||||
status_message = ('📫️ Processing request '
|
status_message = ('📫️ Processing request '
|
||||||
'to fetch data from {}'
|
'to fetch data from {}'
|
||||||
.format(url))
|
.format(url))
|
||||||
await XmppStatus.send(self, jid, status_message, status_type)
|
XmppPresence.send(self, jid, status_message,
|
||||||
|
status_type=status_type)
|
||||||
if url.startswith('feed:'):
|
if url.startswith('feed:'):
|
||||||
url = uri.feed_to_http(url)
|
url = uri.feed_to_http(url)
|
||||||
url = (uri.replace_hostname(url, 'feed')) or url
|
url = (uri.replace_hostname(url, 'feed')) or url
|
||||||
|
@ -605,7 +536,7 @@ async def message(self, message):
|
||||||
# 'of being added to the subscription '
|
# 'of being added to the subscription '
|
||||||
# 'list.'.format(url)
|
# 'list.'.format(url)
|
||||||
# )
|
# )
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('feeds'):
|
case _ if message_lowercase.startswith('feeds'):
|
||||||
query = message_text[6:]
|
query = message_text[6:]
|
||||||
if query:
|
if query:
|
||||||
|
@ -619,14 +550,14 @@ async def message(self, message):
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
result = await sqlite.get_feeds(db_file)
|
result = await sqlite.get_feeds(db_file)
|
||||||
response = action.list_feeds(result)
|
response = action.list_feeds(result)
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case 'goodbye':
|
case 'goodbye':
|
||||||
if message['type'] == 'groupchat':
|
if message['type'] == 'groupchat':
|
||||||
await groupchat.leave(self, jid)
|
await XmppGroupchat.leave(self, jid)
|
||||||
await XmppBookmark.remove(self, muc_jid)
|
await XmppBookmark.remove(self, muc_jid)
|
||||||
else:
|
else:
|
||||||
response = 'This command is valid in groupchat only.'
|
response = 'This command is valid in groupchat only.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('interval'):
|
case _ if message_lowercase.startswith('interval'):
|
||||||
key = message_text[:8]
|
key = message_text[:8]
|
||||||
val = message_text[9:]
|
val = message_text[9:]
|
||||||
|
@ -636,14 +567,14 @@ async def message(self, message):
|
||||||
muc_jid = uri.check_xmpp_uri(message_text[5:])
|
muc_jid = uri.check_xmpp_uri(message_text[5:])
|
||||||
if muc_jid:
|
if muc_jid:
|
||||||
# TODO probe JID and confirm it's a groupchat
|
# TODO probe JID and confirm it's a groupchat
|
||||||
await groupchat.join(self, jid, muc_jid)
|
await XmppGroupchat.join(self, jid, muc_jid)
|
||||||
response = ('Joined groupchat {}'
|
response = ('Joined groupchat {}'
|
||||||
.format(message_text))
|
.format(message_text))
|
||||||
else:
|
else:
|
||||||
response = ('> {}\n'
|
response = ('> {}\n'
|
||||||
'XMPP URI is not valid.'
|
'XMPP URI is not valid.'
|
||||||
.format(message_text))
|
.format(message_text))
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('length'):
|
case _ if message_lowercase.startswith('length'):
|
||||||
key = message_text[:6]
|
key = message_text[:6]
|
||||||
val = message_text[7:]
|
val = message_text[7:]
|
||||||
|
@ -692,7 +623,7 @@ async def message(self, message):
|
||||||
# ).format(val)
|
# ).format(val)
|
||||||
# else:
|
# else:
|
||||||
# response = 'Missing value.'
|
# response = 'Missing value.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case 'new':
|
case 'new':
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
key = 'old'
|
key = 'old'
|
||||||
|
@ -702,7 +633,7 @@ async def message(self, message):
|
||||||
else:
|
else:
|
||||||
await sqlite.set_settings_value(db_file, [key, val])
|
await sqlite.set_settings_value(db_file, [key, val])
|
||||||
response = 'Only new items of newly added feeds will be sent.'
|
response = 'Only new items of newly added feeds will be sent.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
# TODO Will you add support for number of messages?
|
# TODO Will you add support for number of messages?
|
||||||
case 'next':
|
case 'next':
|
||||||
# num = message_text[5:]
|
# num = message_text[5:]
|
||||||
|
@ -739,7 +670,7 @@ async def message(self, message):
|
||||||
else:
|
else:
|
||||||
await sqlite.set_settings_value(db_file, [key, val])
|
await sqlite.set_settings_value(db_file, [key, val])
|
||||||
response = 'All items of newly added feeds will be sent.'
|
response = 'All items of newly added feeds will be sent.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('quantum'):
|
case _ if message_lowercase.startswith('quantum'):
|
||||||
key = message_text[:7]
|
key = message_text[:7]
|
||||||
val = message_text[8:]
|
val = message_text[8:]
|
||||||
|
@ -762,12 +693,12 @@ async def message(self, message):
|
||||||
response = 'Enter a numeric value only.'
|
response = 'Enter a numeric value only.'
|
||||||
else:
|
else:
|
||||||
response = 'Missing value.'
|
response = 'Missing value.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case 'random':
|
case 'random':
|
||||||
# TODO /questions/2279706/select-random-row-from-a-sqlite-table
|
# TODO /questions/2279706/select-random-row-from-a-sqlite-table
|
||||||
# NOTE sqlitehandler.get_entry_unread
|
# NOTE sqlitehandler.get_entry_unread
|
||||||
response = 'Updates will be sent by random order.'
|
response = 'Updates will be sent by random order.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('read'):
|
case _ if message_lowercase.startswith('read'):
|
||||||
data = message_text[5:]
|
data = message_text[5:]
|
||||||
data = data.split()
|
data = data.split()
|
||||||
|
@ -776,7 +707,8 @@ async def message(self, message):
|
||||||
status_type = 'dnd'
|
status_type = 'dnd'
|
||||||
status_message = ('📫️ Processing request to fetch data from {}'
|
status_message = ('📫️ Processing request to fetch data from {}'
|
||||||
.format(url))
|
.format(url))
|
||||||
await XmppStatus.send(self, jid, status_message, status_type)
|
XmppPresence.send(self, jid, status_message,
|
||||||
|
status_type=status_type)
|
||||||
if url.startswith('feed:'):
|
if url.startswith('feed:'):
|
||||||
url = uri.feed_to_http(url)
|
url = uri.feed_to_http(url)
|
||||||
url = (uri.replace_hostname(url, 'feed')) or url
|
url = (uri.replace_hostname(url, 'feed')) or url
|
||||||
|
@ -796,7 +728,7 @@ async def message(self, message):
|
||||||
response = ('Enter command as follows:\n'
|
response = ('Enter command as follows:\n'
|
||||||
'`read <url>` or `read <url> <number>`\n'
|
'`read <url>` or `read <url> <number>`\n'
|
||||||
'URL must not contain white space.')
|
'URL must not contain white space.')
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||||
case _ if message_lowercase.startswith('recent'):
|
case _ if message_lowercase.startswith('recent'):
|
||||||
num = message_text[7:]
|
num = message_text[7:]
|
||||||
|
@ -813,7 +745,7 @@ async def message(self, message):
|
||||||
response = 'Enter a numeric value only.'
|
response = 'Enter a numeric value only.'
|
||||||
else:
|
else:
|
||||||
response = 'Missing value.'
|
response = 'Missing value.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('remove'):
|
case _ if message_lowercase.startswith('remove'):
|
||||||
ix_url = message_text[7:]
|
ix_url = message_text[7:]
|
||||||
if ix_url:
|
if ix_url:
|
||||||
|
@ -859,14 +791,15 @@ async def message(self, message):
|
||||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||||
else:
|
else:
|
||||||
response = 'Missing feed URL or index number.'
|
response = 'Missing feed URL or index number.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('reset'):
|
case _ if message_lowercase.startswith('reset'):
|
||||||
# TODO Reset also by ID
|
# TODO Reset also by ID
|
||||||
ix_url = message_text[6:]
|
ix_url = message_text[6:]
|
||||||
await task.clean_tasks_xmpp(jid, ['status'])
|
await task.clean_tasks_xmpp(jid, ['status'])
|
||||||
status_type = 'dnd'
|
status_type = 'dnd'
|
||||||
status_message = '📫️ Marking entries as read...'
|
status_message = '📫️ Marking entries as read...'
|
||||||
await XmppStatus.send(self, jid, status_message, status_type)
|
XmppPresence.send(self, jid, status_message,
|
||||||
|
status_type=status_type)
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
if ix_url:
|
if ix_url:
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
|
@ -905,7 +838,7 @@ async def message(self, message):
|
||||||
else:
|
else:
|
||||||
await sqlite.mark_all_as_read(db_file)
|
await sqlite.mark_all_as_read(db_file)
|
||||||
response = 'All entries have been marked as read.'
|
response = 'All entries have been marked as read.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||||
case _ if message_lowercase.startswith('search'):
|
case _ if message_lowercase.startswith('search'):
|
||||||
query = message_text[7:]
|
query = message_text[7:]
|
||||||
|
@ -918,25 +851,13 @@ async def message(self, message):
|
||||||
response = 'Enter at least 2 characters to search'
|
response = 'Enter at least 2 characters to search'
|
||||||
else:
|
else:
|
||||||
response = 'Missing search query.'
|
response = 'Missing search query.'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case 'start':
|
case 'start':
|
||||||
# response = 'Updates are enabled.'
|
await action.xmpp_start_updates(self, message, jid, jid_file)
|
||||||
key = 'enabled'
|
|
||||||
val = 1
|
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
|
||||||
if await sqlite.get_settings_value(db_file, key):
|
|
||||||
await sqlite.update_settings_value(db_file, [key, val])
|
|
||||||
else:
|
|
||||||
await sqlite.set_settings_value(db_file, [key, val])
|
|
||||||
await task.start_tasks_xmpp(self, jid)
|
|
||||||
response = 'Updates are enabled.'
|
|
||||||
# print(current_time(), 'task_manager[jid]')
|
|
||||||
# print(task_manager[jid])
|
|
||||||
send_reply_message(self, message, response)
|
|
||||||
case 'stats':
|
case 'stats':
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
response = await action.list_statistics(db_file)
|
response = await action.list_statistics(db_file)
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('disable '):
|
case _ if message_lowercase.startswith('disable '):
|
||||||
ix = message_text[8:]
|
ix = message_text[8:]
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
|
@ -946,7 +867,7 @@ async def message(self, message):
|
||||||
.format(ix))
|
.format(ix))
|
||||||
except:
|
except:
|
||||||
response = 'No news source with index {}.'.format(ix)
|
response = 'No news source with index {}.'.format(ix)
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('enable'):
|
case _ if message_lowercase.startswith('enable'):
|
||||||
ix = message_text[7:]
|
ix = message_text[7:]
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
|
@ -956,29 +877,29 @@ async def message(self, message):
|
||||||
.format(ix))
|
.format(ix))
|
||||||
except:
|
except:
|
||||||
response = 'No news source with index {}.'.format(ix)
|
response = 'No news source with index {}.'.format(ix)
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case 'stop':
|
case 'stop':
|
||||||
await action.xmpp_stop_updates(self, message, jid, jid_file)
|
await action.xmpp_stop_updates(self, message, jid, jid_file)
|
||||||
case 'support':
|
case 'support':
|
||||||
# TODO Send an invitation.
|
# TODO Send an invitation.
|
||||||
response = 'Join xmpp:slixfeed@chat.woodpeckersnest.space?join'
|
response = 'Join xmpp:slixfeed@chat.woodpeckersnest.space?join'
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('xmpp:'):
|
case _ if message_lowercase.startswith('xmpp:'):
|
||||||
muc_jid = uri.check_xmpp_uri(message_text)
|
muc_jid = uri.check_xmpp_uri(message_text)
|
||||||
if muc_jid:
|
if muc_jid:
|
||||||
# TODO probe JID and confirm it's a groupchat
|
# TODO probe JID and confirm it's a groupchat
|
||||||
await groupchat.join(self, jid, muc_jid)
|
await XmppGroupchat.join(self, jid, muc_jid)
|
||||||
response = ('Joined groupchat {}'
|
response = ('Joined groupchat {}'
|
||||||
.format(message_text))
|
.format(message_text))
|
||||||
else:
|
else:
|
||||||
response = ('> {}\n'
|
response = ('> {}\n'
|
||||||
'XMPP URI is not valid.'
|
'XMPP URI is not valid.'
|
||||||
.format(message_text))
|
.format(message_text))
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _:
|
case _:
|
||||||
response = ('Unknown command. '
|
response = ('Unknown command. '
|
||||||
'Press "help" for list of commands')
|
'Press "help" for list of commands')
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
# TODO Use message correction here
|
# TODO Use message correction here
|
||||||
# NOTE This might not be a good idea if
|
# NOTE This might not be a good idea if
|
||||||
# commands are sent one close to the next
|
# commands are sent one close to the next
|
||||||
|
@ -988,7 +909,7 @@ async def message(self, message):
|
||||||
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)
|
||||||
response = 'Finished. Total time: {}s'.format(command_time_total)
|
response = 'Finished. Total time: {}s'.format(command_time_total)
|
||||||
send_reply_message(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
|
|
||||||
if not response: response = 'EMPTY MESSAGE - ACTION ONLY'
|
if not response: response = 'EMPTY MESSAGE - ACTION ONLY'
|
||||||
data_dir = config.get_default_data_directory()
|
data_dir = config.get_default_data_directory()
|
||||||
|
@ -1010,67 +931,3 @@ async def message(self, message):
|
||||||
'{}\n'
|
'{}\n'
|
||||||
.format(message_text, jid, jid_file, response)
|
.format(message_text, jid, jid_file, response)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def send_reply_message(self, message, response):
|
|
||||||
message.reply(response).send()
|
|
||||||
|
|
||||||
|
|
||||||
# TODO Solve this function
|
|
||||||
def send_oob_reply_message(message, url, response):
|
|
||||||
reply = message.reply(response)
|
|
||||||
reply['oob']['url'] = url
|
|
||||||
reply.send()
|
|
||||||
|
|
||||||
|
|
||||||
async def send_oob_message(self, jid, url):
|
|
||||||
chat_type = await get_chat_type(self, jid)
|
|
||||||
html = (
|
|
||||||
f'<body xmlns="http://www.w3.org/1999/xhtml">'
|
|
||||||
f'<a href="{url}">{url}</a></body>')
|
|
||||||
message = self.make_message(
|
|
||||||
mto=jid,
|
|
||||||
mfrom=self.boundjid.bare,
|
|
||||||
mbody=url,
|
|
||||||
mhtml=html,
|
|
||||||
mtype=chat_type
|
|
||||||
)
|
|
||||||
message['oob']['url'] = url
|
|
||||||
message.send()
|
|
||||||
|
|
||||||
|
|
||||||
# def greet(self, jid, chat_type='chat'):
|
|
||||||
# messages = [
|
|
||||||
# 'Greetings!',
|
|
||||||
# 'I'm {}, the news anchor.'.format(self.nick),
|
|
||||||
# 'My job is to bring you the latest news '
|
|
||||||
# 'from sources you provide me with.',
|
|
||||||
# 'You may always reach me via '
|
|
||||||
# 'xmpp:{}?message'.format(self.boundjid.bare)
|
|
||||||
# ]
|
|
||||||
# for message in messages:
|
|
||||||
# self.send_message(
|
|
||||||
# mto=jid,
|
|
||||||
# mfrom=self.boundjid.bare,
|
|
||||||
# mbody=message,
|
|
||||||
# mtype=chat_type
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
def greet(self, jid, chat_type='chat'):
|
|
||||||
message = (
|
|
||||||
'Greetings!\n'
|
|
||||||
'I am {}, the news anchor.\n'
|
|
||||||
'My job is to bring you the latest '
|
|
||||||
'news from sources you provide me with.\n'
|
|
||||||
'You may always reach me via xmpp:{}?message').format(
|
|
||||||
self.alias,
|
|
||||||
self.boundjid.bare
|
|
||||||
)
|
|
||||||
self.send_message(
|
|
||||||
mto=jid,
|
|
||||||
mfrom=self.boundjid.bare,
|
|
||||||
mbody=message,
|
|
||||||
mtype=chat_type
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
|
@ -10,65 +10,40 @@ TODO
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import slixfeed.xmpp.utility as utility
|
class XmppRoster:
|
||||||
|
|
||||||
async def remove(self, jid):
|
async def remove(self, jid):
|
||||||
"""
|
"""
|
||||||
Remove JID to roster.
|
Remove JID to roster.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
jid : str
|
jid : str
|
||||||
Jabber ID.
|
Jabber ID.
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
None.
|
None.
|
||||||
"""
|
"""
|
||||||
self.update_roster(
|
self.update_roster(jid, subscription="remove")
|
||||||
jid,
|
|
||||||
subscription="remove"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def add(self, jid):
|
async def add(self, jid):
|
||||||
"""
|
"""
|
||||||
Add JID to roster.
|
Add JID to roster.
|
||||||
|
|
||||||
Parameters
|
Add JID to roster if it is not already in roster.
|
||||||
----------
|
|
||||||
jid : str
|
|
||||||
Jabber ID.
|
|
||||||
|
|
||||||
Returns
|
Parameters
|
||||||
-------
|
----------
|
||||||
None.
|
jid : str
|
||||||
"""
|
Jabber ID.
|
||||||
if await utility.get_chat_type(self, jid) == "groupchat":
|
|
||||||
# Check whether JID is in bookmarks; otherwise, add it.
|
Returns
|
||||||
print(jid, "is muc")
|
-------
|
||||||
return
|
None.
|
||||||
else:
|
"""
|
||||||
await self.get_roster()
|
await self.get_roster()
|
||||||
# Check whether JID is in roster; otherwise, add it.
|
|
||||||
if jid not in self.client_roster.keys():
|
if jid not in self.client_roster.keys():
|
||||||
self.send_presence_subscription(
|
self.update_roster(jid, subscription="both")
|
||||||
pto=jid,
|
|
||||||
pfrom=self.boundjid.bare,
|
|
||||||
ptype="subscribe",
|
|
||||||
pnick=self.alias
|
|
||||||
)
|
|
||||||
self.update_roster(
|
|
||||||
jid,
|
|
||||||
subscription="both"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_subscription(self):
|
|
||||||
"""
|
|
||||||
Remove subscription from contacts that don't share their presence.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
None.
|
|
||||||
"""
|
|
|
@ -1,71 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from slixmpp.xmlstream.matcher import MatchXPath
|
|
||||||
from slixmpp.xmlstream.handler import Callback
|
|
||||||
from slixmpp.xmlstream import ET
|
|
||||||
|
|
||||||
async def request(self, jid):
|
|
||||||
"""
|
|
||||||
Ask contant to settle subscription.
|
|
||||||
|
|
||||||
Parameters
|
|
||||||
----------
|
|
||||||
jid : str
|
|
||||||
Jabber ID.
|
|
||||||
|
|
||||||
Returns
|
|
||||||
-------
|
|
||||||
None.
|
|
||||||
"""
|
|
||||||
# Check whether JID is subscribed; otherwise, ask for presence.
|
|
||||||
if self.is_component:
|
|
||||||
presence_probe = ET.Element('presence')
|
|
||||||
presence_probe.attrib['type'] = 'probe'
|
|
||||||
presence_probe.attrib['to'] = jid
|
|
||||||
print(presence_probe)
|
|
||||||
breakpoint()
|
|
||||||
self.send_raw(str(presence_probe))
|
|
||||||
presence_probe.send()
|
|
||||||
elif not self.client_roster[jid]["to"]:
|
|
||||||
self.send_presence_subscription(
|
|
||||||
pto=jid,
|
|
||||||
pfrom=self.boundjid.bare,
|
|
||||||
ptype="subscribe",
|
|
||||||
pnick=self.alias
|
|
||||||
)
|
|
||||||
self.send_message(
|
|
||||||
mto=jid,
|
|
||||||
mfrom=self.boundjid.bare,
|
|
||||||
# mtype="headline",
|
|
||||||
msubject="RSS News Bot",
|
|
||||||
mbody=(
|
|
||||||
"Share online status to receive updates."
|
|
||||||
),
|
|
||||||
mnick=self.alias
|
|
||||||
)
|
|
||||||
self.send_presence(
|
|
||||||
pto=jid,
|
|
||||||
pfrom=self.boundjid.bare,
|
|
||||||
# Accept symbol 🉑️ 👍️ ✍
|
|
||||||
pstatus=(
|
|
||||||
"✒️ Share online status to receive updates."
|
|
||||||
),
|
|
||||||
# ptype="subscribe",
|
|
||||||
pnick=self.alias
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def unsubscribed(self, presence):
|
|
||||||
jid = presence["from"].bare
|
|
||||||
self.send_message(
|
|
||||||
mto=jid,
|
|
||||||
mfrom=self.boundjid.bare,
|
|
||||||
mbody="You have been unsubscribed."
|
|
||||||
)
|
|
||||||
self.send_presence(
|
|
||||||
pto=jid,
|
|
||||||
pfrom=self.boundjid.bare,
|
|
||||||
pstatus="🖋️ Subscribe to receive updates",
|
|
||||||
pnick=self.alias
|
|
||||||
)
|
|
|
@ -1,19 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from slixfeed.xmpp.utility import get_chat_type
|
|
||||||
|
|
||||||
|
|
||||||
class XmppStatus:
|
|
||||||
|
|
||||||
|
|
||||||
async def send(self, jid, status_message, status_type=None, chat_type=None):
|
|
||||||
if not chat_type:
|
|
||||||
chat_type = await get_chat_type(self, jid)
|
|
||||||
self.send_presence(
|
|
||||||
pto=jid,
|
|
||||||
pfrom=self.boundjid.bare,
|
|
||||||
pshow=status_type,
|
|
||||||
pstatus=status_message,
|
|
||||||
ptype=chat_type
|
|
||||||
)
|
|
|
@ -11,38 +11,39 @@ 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
|
# import sys
|
||||||
|
|
||||||
|
class XmppUpload:
|
||||||
|
|
||||||
async def start(self, jid, filename, domain=None):
|
async def start(self, jid, filename, domain=None):
|
||||||
logging.info('Uploading file %s...', filename)
|
logging.info('Uploading file %s...', filename)
|
||||||
try:
|
|
||||||
upload_file = self['xep_0363'].upload_file
|
|
||||||
# if self.encrypted and not self['xep_0454']:
|
|
||||||
# print(
|
|
||||||
# 'The xep_0454 module isn\'t available. '
|
|
||||||
# 'Ensure you have \'cryptography\' '
|
|
||||||
# 'from extras_require installed.',
|
|
||||||
# file=sys.stderr,
|
|
||||||
# )
|
|
||||||
# return
|
|
||||||
# elif self.encrypted:
|
|
||||||
# upload_file = self['xep_0454'].upload_file
|
|
||||||
try:
|
try:
|
||||||
url = await upload_file(
|
upload_file = self['xep_0363'].upload_file
|
||||||
filename, domain, timeout=10,
|
# if self.encrypted and not self['xep_0454']:
|
||||||
)
|
# print(
|
||||||
logging.info('Upload successful!')
|
# 'The xep_0454 module isn\'t available. '
|
||||||
logging.info('Sending file to %s', jid)
|
# 'Ensure you have \'cryptography\' '
|
||||||
except HTTPError:
|
# 'from extras_require installed.',
|
||||||
url = (
|
# file=sys.stderr,
|
||||||
"Error: It appears that this server doesn't support "
|
|
||||||
"HTTP File Upload."
|
|
||||||
)
|
|
||||||
logging.error(
|
|
||||||
"It appears that this server doesn't support HTTP File Upload."
|
|
||||||
)
|
|
||||||
# raise HTTPError(
|
|
||||||
# "This server doesn't appear to support HTTP File Upload"
|
|
||||||
# )
|
# )
|
||||||
except IqTimeout:
|
# return
|
||||||
raise TimeoutError('Could not send message in time')
|
# elif self.encrypted:
|
||||||
return url
|
# upload_file = self['xep_0454'].upload_file
|
||||||
|
try:
|
||||||
|
url = await upload_file(
|
||||||
|
filename, domain, timeout=10,
|
||||||
|
)
|
||||||
|
logging.info('Upload successful!')
|
||||||
|
logging.info('Sending file to %s', jid)
|
||||||
|
except HTTPError:
|
||||||
|
url = (
|
||||||
|
"Error: It appears that this server doesn't support "
|
||||||
|
"HTTP File Upload."
|
||||||
|
)
|
||||||
|
logging.error(
|
||||||
|
"It appears that this server doesn't support HTTP File Upload."
|
||||||
|
)
|
||||||
|
# raise HTTPError(
|
||||||
|
# "This server doesn't appear to support HTTP File Upload"
|
||||||
|
# )
|
||||||
|
except IqTimeout:
|
||||||
|
raise TimeoutError('Could not send message in time')
|
||||||
|
return url
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from slixmpp.exceptions import IqTimeout
|
from slixmpp.exceptions import IqError, IqTimeout
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
# class XmppChat
|
||||||
|
# class XmppUtility:
|
||||||
|
|
||||||
async def get_chat_type(self, jid):
|
async def get_chat_type(self, jid):
|
||||||
"""
|
"""
|
||||||
|
@ -43,11 +45,15 @@ async def get_chat_type(self, jid):
|
||||||
'Chat Type: {}'.format(jid, chat_type))
|
'Chat Type: {}'.format(jid, chat_type))
|
||||||
return chat_type
|
return chat_type
|
||||||
# TODO Test whether this exception is realized
|
# TODO Test whether this exception is realized
|
||||||
|
except IqError as e:
|
||||||
|
message = ('IQ Error\n'
|
||||||
|
'IQ Stanza: {}'
|
||||||
|
'Jabber ID: {}'
|
||||||
|
.format(e, jid))
|
||||||
|
logging.error(message)
|
||||||
except IqTimeout as e:
|
except IqTimeout as e:
|
||||||
messages = [
|
message = ('IQ Timeout\n'
|
||||||
("Timeout IQ"),
|
'IQ Stanza: {}'
|
||||||
("IQ Stanza:", e),
|
'Jabber ID: {}'
|
||||||
("Jabber ID:", jid)
|
.format(e, jid))
|
||||||
]
|
logging.error(message)
|
||||||
for message in messages:
|
|
||||||
logging.error(message)
|
|
||||||
|
|
Loading…
Reference in a new issue