Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
39781d0149
|
|||
|
94e9b155ef
|
|||
|
38b8a2fdf6
|
|||
|
325316c3b2
|
|||
|
68800cf823
|
|||
|
|
179785ce4e | ||
|
|
ade6439157 | ||
|
|
0812b6c1e8 | ||
|
|
92e708a10b | ||
|
|
255846954a | ||
|
|
339ad336e2 | ||
|
|
2bff450e80 | ||
|
|
e53ecc76da | ||
|
|
6559d236d1 | ||
|
|
f8587a26ca | ||
|
|
65a820b27a | ||
|
|
c3a9420ad7 | ||
|
|
0ef7d9d1de | ||
|
|
eb87f21922 | ||
|
|
3972260733 | ||
|
|
efa13667ca | ||
|
|
f5956dddf0 | ||
|
|
ab9a606473 | ||
|
|
6567aae509 | ||
|
|
a479d2da7d | ||
|
|
2d9793cf32 | ||
|
|
55da731bf6 | ||
|
|
fdb6d70f63 | ||
|
|
19ff42c94f | ||
|
|
8a3089b5be | ||
|
|
d69df863fe | ||
|
|
c49d29846c | ||
|
|
16cb1452c0 | ||
|
|
4f9f513c08 | ||
|
|
9fb6ea1cf3 | ||
|
|
c0eefa2ff7 | ||
|
|
e84dd620c8 | ||
|
|
ce1c777338 | ||
|
|
148c4b3ee1 | ||
|
|
3f6ac94acb | ||
|
|
3bbe6c6202 | ||
|
|
ff4b5198d8 | ||
|
|
e2ab722f93 | ||
|
|
3f11319a5b | ||
|
|
39f5a03e78 | ||
|
|
cd92ab06d3 | ||
|
|
9506e24609 | ||
|
|
da276cb2e8 | ||
|
|
18c2fc0654 | ||
|
|
b578b5d720 | ||
|
|
b8f03164ee | ||
|
|
409c383937 | ||
|
|
16e6d7257a | ||
|
|
9be0cdf568 | ||
|
|
009a5c79a3 | ||
|
|
72542b75dc | ||
|
|
afc2a585a3 | ||
|
|
b7c758161d | ||
|
|
83ec503ea9 | ||
|
|
c02c159e24 | ||
|
|
217f4e3c99 | ||
|
|
d5dcd54ec8 | ||
|
|
3036624725 | ||
|
|
042e626423 | ||
|
|
05b3d69cbb | ||
|
|
dc057d40a7 | ||
|
|
d80767f1c4 | ||
|
|
9a2234a1b4 | ||
|
|
47acbc76ac | ||
|
|
1250d1df42 | ||
|
|
c39550cd1c | ||
|
|
38c06599c1 | ||
|
|
32ad1708a9 | ||
|
|
dfd7b09d9e | ||
|
|
91558b7f06 | ||
|
|
6d954537b9 | ||
|
|
b8a19f3cff | ||
|
|
77c2eb0f56 | ||
|
|
eeb1c0e214 | ||
|
|
2a20b83f53 | ||
|
|
64a97f5177 | ||
|
|
9c7f05305b | ||
|
|
ff23b5b2ce | ||
|
|
ef43aa0267 | ||
|
|
8cf42e000b | ||
|
|
2895411eb6 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1 +1,2 @@
|
|||||||
*.so
|
*.so
|
||||||
|
.idea/
|
||||||
|
|||||||
16
ChatStart.rb
16
ChatStart.rb
@@ -1,16 +0,0 @@
|
|||||||
module ChatStart
|
|
||||||
|
|
||||||
@@starts = {
|
|
||||||
"prof1@panesar" => [ "\"Prof 2\"", "prof3@panesar" ],
|
|
||||||
"prof2@panesar" => [ "prof1@panesar" ]
|
|
||||||
}
|
|
||||||
|
|
||||||
def self.prof_on_connect(account_name, fulljid)
|
|
||||||
if @@starts[account_name]
|
|
||||||
@@starts[account_name].each { | contact |
|
|
||||||
Prof::send_line("/msg " + contact)
|
|
||||||
}
|
|
||||||
Prof::send_line("/win 1")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
124
README.md
124
README.md
@@ -1,110 +1,56 @@
|
|||||||
profanity-plugins
|
# CProof Plugins
|
||||||
=================
|
|
||||||
|
|
||||||
Plugin support for Profanity is currently in development.
|
[Website documentation](https://jabber.space/guides/plugins/)
|
||||||
|
|
||||||
* The `master` branch of Profanity now includes support for C and Python plugins.
|
`Master` is a development branch compatible with the latest version of CProof.
|
||||||
* The `plugins` branch contains additional support for Ruby and Lua, but is unstable.
|
|
||||||
|
|
||||||
For a list of outstanding issues before releasing 0.5.0, see: https://github.com/boothj5/profanity/milestones/0.5.0
|
## Installing plugins
|
||||||
|
|
||||||
Building Profanity with plugin support
|
Use the `/plugins install` command, e.g.
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
Additional dependencies required:
|
```bash
|
||||||
|
/plugins install ~/path-to/sounds.py
|
||||||
|
```
|
||||||
|
|
||||||
|
Alternatively, you can use URLs to raw files to install Python plugins. For example,
|
||||||
|
```bash
|
||||||
|
/plugins install https://git.jabber.space/devs/cproof-plugins/raw/branch/master/src/sounds.py
|
||||||
|
```
|
||||||
|
|
||||||
|
See the `/help plugins` command for further plugin management options.
|
||||||
|
|
||||||
|
## Plugins description
|
||||||
|
|
||||||
|
To be described.
|
||||||
|
|
||||||
|
## Building CProof with plugin support
|
||||||
|
|
||||||
|
Dependencies required:
|
||||||
|
|
||||||
```
|
```
|
||||||
autoconf-archive
|
autoconf-archive
|
||||||
libtool
|
libtool
|
||||||
```
|
```
|
||||||
|
|
||||||
Plus the development packages for supported languages:
|
For Python plugins the following is also required:
|
||||||
|
|
||||||
```
|
```
|
||||||
python-dev
|
python-dev
|
||||||
lua-dev
|
|
||||||
ruby-dev
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Build with:
|
## Developing plugins
|
||||||
|
|
||||||
```
|
API Documentation is available on our website, [jabber.space](https://jabber.space/).
|
||||||
./bootstrap.sh
|
- [Python API](https://jabber.space/api-reference/python/prof/)
|
||||||
./configure --enable-python-plugins
|
- [Python hooks](https://jabber.space/api-reference/python/plugin/)
|
||||||
make
|
- [C API](https://jabber.space/api-reference/c/profapi/)
|
||||||
sudo make install
|
- [C hooks](https://jabber.space/api-reference/c/profhooks/)
|
||||||
```
|
|
||||||
|
|
||||||
Only support for Python 2.7 is currently included, after building, run `profanity -v` to see which language support is available, example output:
|
## External plugins (C)
|
||||||
|
|
||||||
```
|
- [profanity-plugins by Reimar](https://github.com/ReimarPB/profanity-plugins) - Collection of plugins
|
||||||
Profanity, version 0.5.0dev.plugins-python.63a7316
|
|
||||||
Copyright (C) 2012 - 2016 James Booth <boothj5web@gmail.com>.
|
|
||||||
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
|
||||||
|
|
||||||
This is free software; you are free to change and redistribute it.
|
|
||||||
There is NO WARRANTY, to the extent permitted by law.
|
|
||||||
|
|
||||||
Build information:
|
|
||||||
XMPP library: libmesode
|
|
||||||
Desktop notification support: Enabled
|
|
||||||
OTR support: Enabled
|
|
||||||
PGP support: Enabled
|
|
||||||
C plugins: Enabled
|
|
||||||
Python plugins: Enabled
|
|
||||||
```
|
|
||||||
|
|
||||||
Installing plugins
|
|
||||||
------------------
|
|
||||||
|
|
||||||
1 - Copy the plugin
|
|
||||||
|
|
||||||
For Python, Ruby and Lua plugins, copy the plugin to `$XDG_DATA/profanity/plugins/`, (`~/.local/share/profanity/plugins/` on most systems).
|
|
||||||
|
|
||||||
For C plugins, build the plugin using the supplied Makefile, and then copy the `.so` file to the same location.
|
|
||||||
|
|
||||||
2 - Load the plugin
|
|
||||||
|
|
||||||
Run the `/plugins load <plugin>` command to load the plugin, e.g. `/plugins load browser.py`, the plugin can also be manually added to the config file `$XDG_CONFIG/profanity/profrc` (`~/.config/profanity/profrc` on most systems).
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
```
|
|
||||||
[plugins]
|
|
||||||
load=browser.py;platform-info.py;ascii.py;pid.so
|
|
||||||
```
|
|
||||||
|
|
||||||
Getting help on plugins:
|
|
||||||
|
|
||||||
* `/plugins` - Shows a list of loaded plugins.
|
|
||||||
* `/help commands plugins` - Shows commands defined by plugins
|
|
||||||
* `/help <plugin_cmd>` - Show help for a plugin command, e.g. `/help browser`
|
|
||||||
|
|
||||||
Plugin themes
|
|
||||||
-------------
|
|
||||||
|
|
||||||
The plugins API includes functions to print themed output to the console or a plugins window. The themes need to be added to
|
|
||||||
|
|
||||||
```
|
|
||||||
~/.local/share/profanity/plugin_themes
|
|
||||||
```
|
|
||||||
|
|
||||||
For example ([syscmd.py](https://github.com/boothj5/profanity-plugins/blob/master/syscmd.py) plugin):
|
|
||||||
|
|
||||||
```
|
|
||||||
[system]
|
|
||||||
command=cyan
|
|
||||||
result=green
|
|
||||||
```
|
|
||||||
|
|
||||||
Example plugin code
|
|
||||||
-------------------
|
|
||||||
|
|
||||||
Whilst the API is being developed, the following test plugins are a good reference of possible hooks and API calls available, (Ruby and Lua examples might not be up to date):
|
|
||||||
|
|
||||||
* [tests/test-c-plugin.c](https://github.com/boothj5/profanity-plugins/blob/master/tests/test-c-plugin/test-c-plugin.c)
|
|
||||||
* [tests/python-test.py](https://github.com/boothj5/profanity-plugins/blob/master/tests/python-test.py)
|
|
||||||
* [tests/RubyTest.rb](https://github.com/boothj5/profanity-plugins/blob/master/tests/RubyTest.rb)
|
|
||||||
* [tests/luatest.lua](https://github.com/boothj5/profanity-plugins/blob/master/tests/luatest.lua)
|
|
||||||
|
|
||||||
|
|
||||||
|
## External plugins (Python)
|
||||||
|
|
||||||
|
- [profanity-copy-message-plugin](https://github.com/lonski/profanity-copy-message-plugin) - Copy messages to clipboard.
|
||||||
|
|||||||
175
browser.py
175
browser.py
@@ -1,175 +0,0 @@
|
|||||||
"""
|
|
||||||
Open the last link received in a chat or room window using the systems default browser
|
|
||||||
"""
|
|
||||||
|
|
||||||
import prof
|
|
||||||
import os
|
|
||||||
import webbrowser
|
|
||||||
import re
|
|
||||||
import requests
|
|
||||||
from os.path import expanduser
|
|
||||||
|
|
||||||
_links = {}
|
|
||||||
_lastlink = {}
|
|
||||||
|
|
||||||
|
|
||||||
def _get_url():
|
|
||||||
link = None
|
|
||||||
jid = prof.get_current_recipient()
|
|
||||||
room = prof.get_current_muc()
|
|
||||||
|
|
||||||
# check if in chat window
|
|
||||||
if jid is not None:
|
|
||||||
|
|
||||||
# check for link from recipient
|
|
||||||
if jid in _lastlink.keys():
|
|
||||||
link = _lastlink[jid]
|
|
||||||
else:
|
|
||||||
prof.cons_show("No links found from " + jid)
|
|
||||||
|
|
||||||
# check if in muc window
|
|
||||||
elif room is not None:
|
|
||||||
if room in _lastlink.keys():
|
|
||||||
link = _lastlink[room]
|
|
||||||
else:
|
|
||||||
prof.cons_show("No links found in " + room)
|
|
||||||
|
|
||||||
# not in chat/muc window
|
|
||||||
else:
|
|
||||||
prof.cons_show("You must supply a URL to the /browser command")
|
|
||||||
|
|
||||||
return link
|
|
||||||
|
|
||||||
def _cmd_browser(arg1=None, arg2=None):
|
|
||||||
global _lastlink
|
|
||||||
link = None
|
|
||||||
|
|
||||||
if arg1 == "setdir":
|
|
||||||
if not arg2:
|
|
||||||
prof.cons_bad_cmd_usage("/browser")
|
|
||||||
else:
|
|
||||||
prof.settings_set_string("browser", "download.path", arg2)
|
|
||||||
prof.cons_show("browser.py set download path to" + arg2)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
if arg1 == "get":
|
|
||||||
link = arg2 if arg2 is not None else _get_url()
|
|
||||||
|
|
||||||
if not link:
|
|
||||||
prof.log_debug("browser.py: no link found for get command")
|
|
||||||
return
|
|
||||||
|
|
||||||
folder = prof.settings_get_string("browser", "download.path", "")
|
|
||||||
if folder == "":
|
|
||||||
prof.cons_show("Download path not set, see /help browser")
|
|
||||||
return
|
|
||||||
|
|
||||||
if folder[0] == '~':
|
|
||||||
folder = expanduser("~") + folder[1:]
|
|
||||||
|
|
||||||
response = requests.get(link)
|
|
||||||
if response.status_code != 200:
|
|
||||||
prof.log_debug("browser.py: received non 200 response for get command")
|
|
||||||
return
|
|
||||||
|
|
||||||
filename = link.split("/")[-1]
|
|
||||||
full_path = folder + "/" + filename
|
|
||||||
prof.log_debug("browser.py: Saving link {link} to file {file}".format(link=link, file=full_path))
|
|
||||||
with open(full_path, 'wb') as f:
|
|
||||||
for chunk in response.iter_content(8):
|
|
||||||
f.write(chunk)
|
|
||||||
|
|
||||||
return
|
|
||||||
|
|
||||||
link = arg1 if arg1 is not None else _get_url();
|
|
||||||
if link is not None:
|
|
||||||
prof.cons_show("Opening " + link + " in browser")
|
|
||||||
_open_browser(link)
|
|
||||||
|
|
||||||
|
|
||||||
def _open_browser(url):
|
|
||||||
savout = os.dup(1)
|
|
||||||
saverr = os.dup(2)
|
|
||||||
os.close(1)
|
|
||||||
os.close(2)
|
|
||||||
os.open(os.devnull, os.O_RDWR)
|
|
||||||
try:
|
|
||||||
webbrowser.open(url, new=2)
|
|
||||||
finally:
|
|
||||||
os.dup2(savout, 1)
|
|
||||||
os.dup2(saverr, 2)
|
|
||||||
|
|
||||||
|
|
||||||
def prof_init(version, status, account_name, fulljid):
|
|
||||||
synopsis = [
|
|
||||||
"/browser",
|
|
||||||
"/browser <url>",
|
|
||||||
"/browser get <url>",
|
|
||||||
"/browser setdir <folder>"
|
|
||||||
]
|
|
||||||
description = (
|
|
||||||
"View a URL in the systems default browser, or download and view link contents " +
|
|
||||||
"If no argument is supplied, the last URL in the current chat or room will be used. " +
|
|
||||||
"Tab autocompletion will go through all previous links in the current chat/room"
|
|
||||||
)
|
|
||||||
args = [
|
|
||||||
[ "<url>", "URL to open in the browser" ],
|
|
||||||
[ "download <url>", "Download contents of specified URL" ],
|
|
||||||
[ "setdir <dir>", "Filesystem path to store downloaded content" ]
|
|
||||||
]
|
|
||||||
examples = [
|
|
||||||
"/browser http://www.profanity.im",
|
|
||||||
"/browser setdir ~/Downloads",
|
|
||||||
"/browser get http://www.movenoticias.com/wp-content/uploads/2015/05/Bruce-Iron-Maiden-850x583.jpg"
|
|
||||||
]
|
|
||||||
|
|
||||||
prof.register_command("/browser", 0, 2, synopsis, description, args, examples, _cmd_browser)
|
|
||||||
prof.completer_add("/browser", [ "get", "setdir" ])
|
|
||||||
|
|
||||||
|
|
||||||
def prof_on_chat_win_focus(jid):
|
|
||||||
prof.completer_clear("/browser")
|
|
||||||
if jid in _links:
|
|
||||||
prof.completer_add("/browser", _links[jid])
|
|
||||||
|
|
||||||
|
|
||||||
def prof_on_room_win_focus(room):
|
|
||||||
prof.completer_clear("/browser")
|
|
||||||
if room in _links:
|
|
||||||
prof.completer_add("/browser", _links[room])
|
|
||||||
|
|
||||||
|
|
||||||
def _process_message(jid, current_jid, message):
|
|
||||||
links = re.findall(r'(https?://\S+)', message)
|
|
||||||
if len(links) > 0:
|
|
||||||
if jid not in _links:
|
|
||||||
_links[jid] = []
|
|
||||||
|
|
||||||
# add to list of links for jid
|
|
||||||
for link in links:
|
|
||||||
if link not in _links[jid]:
|
|
||||||
prof.log_debug("browser.py: Saving {link} for {jid}".format(link=link, jid=jid))
|
|
||||||
_links[jid].append(link)
|
|
||||||
|
|
||||||
# add to autocompleter if message for current window
|
|
||||||
if current_jid == jid:
|
|
||||||
prof.completer_add("/browser", _links[jid])
|
|
||||||
|
|
||||||
# set last link for jid
|
|
||||||
_lastlink[jid] = links[len(links)-1]
|
|
||||||
|
|
||||||
|
|
||||||
def prof_post_chat_message_display(jid, message):
|
|
||||||
current_jid = prof.get_current_recipient()
|
|
||||||
_process_message(jid, current_jid, message)
|
|
||||||
|
|
||||||
|
|
||||||
def prof_post_room_message_display(room, nick, message):
|
|
||||||
current_jid = prof.get_current_muc()
|
|
||||||
_process_message(room, current_jid, message)
|
|
||||||
|
|
||||||
|
|
||||||
def prof_on_room_history_message(room, nick, message, timestamp):
|
|
||||||
current_jid = prof.get_current_muc()
|
|
||||||
_process_message(room, current_jid, message)
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
import prof
|
|
||||||
from chatterbotapi import ChatterBotFactory, ChatterBotType
|
|
||||||
|
|
||||||
|
|
||||||
factory = ChatterBotFactory()
|
|
||||||
bot = factory.create(ChatterBotType.CLEVERBOT)
|
|
||||||
# bot = factory.create(ChatterBotType.JABBERWACKY)
|
|
||||||
# bot = factory.create(ChatterBotType.PANDORABOTS, 'b0dafd24ee35a477')
|
|
||||||
bot_session = {}
|
|
||||||
bot_state = False
|
|
||||||
|
|
||||||
|
|
||||||
def prof_post_chat_message_display(jid, message):
|
|
||||||
if bot_state:
|
|
||||||
if jid not in bot_session:
|
|
||||||
bot_session[jid] = bot.create_session()
|
|
||||||
response = bot_session[jid].think(message)
|
|
||||||
prof.send_line("/msg " + jid + " " + response)
|
|
||||||
|
|
||||||
|
|
||||||
def _cmd_chatterbot(state):
|
|
||||||
global bot_state
|
|
||||||
|
|
||||||
if state == "enable":
|
|
||||||
prof.cons_show("ChatterBot Activated")
|
|
||||||
bot_state = True
|
|
||||||
elif state == "disable":
|
|
||||||
prof.cons_show("ChatterBot Stopped")
|
|
||||||
bot_state = False
|
|
||||||
else:
|
|
||||||
if bot_state:
|
|
||||||
prof.cons_show("ChatterBot is running - current sessions:")
|
|
||||||
prof.cons_show(str(bot_session))
|
|
||||||
else:
|
|
||||||
prof.cons_show("ChatterBot is stopped - /chatterbot enable to activate.")
|
|
||||||
|
|
||||||
|
|
||||||
def prof_init(version, status, account_name, fulljid):
|
|
||||||
synopsis = [
|
|
||||||
"/chatterbot",
|
|
||||||
"/chatterbot enable|disable"
|
|
||||||
]
|
|
||||||
description = "ChatterBot, running with no args will show the current chatterbot status"
|
|
||||||
args = [
|
|
||||||
[ "enable", "Enable chatterbot" ],
|
|
||||||
[ "disable", "Disable chatterbot" ]
|
|
||||||
]
|
|
||||||
examples = []
|
|
||||||
|
|
||||||
prof.register_command("/chatterbot", 0, 1, synopsis, description, args, examples, _cmd_chatterbot)
|
|
||||||
prof.completer_add("/chatterbot", [ "enable", "disable" ])
|
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
import re
|
|
||||||
import sys
|
|
||||||
import hashlib
|
|
||||||
|
|
||||||
if sys.version_info >= (3, 0):
|
|
||||||
from urllib.request import build_opener, HTTPCookieProcessor, urlopen
|
|
||||||
from urllib.parse import urlencode
|
|
||||||
import http.cookiejar as cookielib
|
|
||||||
|
|
||||||
else:
|
|
||||||
from urllib import urlencode, urlopen
|
|
||||||
from urllib2 import build_opener, HTTPCookieProcessor
|
|
||||||
import cookielib
|
|
||||||
|
|
||||||
import uuid
|
|
||||||
import xml.dom.minidom
|
|
||||||
|
|
||||||
"""
|
|
||||||
chatterbotapi
|
|
||||||
Copyright (C) 2011 pierredavidbelanger@gmail.com
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Lesser General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU Lesser General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
"""
|
|
||||||
|
|
||||||
#################################################
|
|
||||||
# API
|
|
||||||
#################################################
|
|
||||||
|
|
||||||
class ChatterBotType:
|
|
||||||
|
|
||||||
CLEVERBOT = 1
|
|
||||||
JABBERWACKY = 2
|
|
||||||
PANDORABOTS = 3
|
|
||||||
|
|
||||||
class ChatterBotFactory:
|
|
||||||
|
|
||||||
def create(self, type, arg = None):
|
|
||||||
if type == ChatterBotType.CLEVERBOT:
|
|
||||||
return _Cleverbot('http://www.cleverbot.com', 'http://www.cleverbot.com/webservicemin', 35)
|
|
||||||
elif type == ChatterBotType.JABBERWACKY:
|
|
||||||
return _Cleverbot('http://jabberwacky.com', 'http://jabberwacky.com/webservicemin', 29)
|
|
||||||
elif type == ChatterBotType.PANDORABOTS:
|
|
||||||
if arg == None:
|
|
||||||
raise Exception('PANDORABOTS needs a botid arg')
|
|
||||||
return _Pandorabots(arg)
|
|
||||||
return None
|
|
||||||
|
|
||||||
class ChatterBot:
|
|
||||||
|
|
||||||
def create_session(self):
|
|
||||||
return None
|
|
||||||
|
|
||||||
class ChatterBotSession:
|
|
||||||
|
|
||||||
def think_thought(self, thought):
|
|
||||||
return thought
|
|
||||||
|
|
||||||
def think(self, text):
|
|
||||||
thought = ChatterBotThought()
|
|
||||||
thought.text = text
|
|
||||||
return self.think_thought(thought).text
|
|
||||||
|
|
||||||
class ChatterBotThought:
|
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
#################################################
|
|
||||||
# Cleverbot impl
|
|
||||||
#################################################
|
|
||||||
|
|
||||||
class _Cleverbot(ChatterBot):
|
|
||||||
|
|
||||||
def __init__(self, baseUrl, serviceUrl, endIndex):
|
|
||||||
self.baseUrl = baseUrl
|
|
||||||
self.serviceUrl = serviceUrl
|
|
||||||
self.endIndex = endIndex
|
|
||||||
|
|
||||||
def create_session(self):
|
|
||||||
return _CleverbotSession(self)
|
|
||||||
|
|
||||||
class _CleverbotSession(ChatterBotSession):
|
|
||||||
|
|
||||||
def __init__(self, bot):
|
|
||||||
self.bot = bot
|
|
||||||
self.vars = {}
|
|
||||||
self.vars['start'] = 'y'
|
|
||||||
self.vars['icognoid'] = 'wsf'
|
|
||||||
self.vars['fno'] = '0'
|
|
||||||
self.vars['sub'] = 'Say'
|
|
||||||
self.vars['islearning'] = '1'
|
|
||||||
self.vars['cleanslate'] = 'false'
|
|
||||||
self.cookieJar = cookielib.CookieJar()
|
|
||||||
self.opener = build_opener(HTTPCookieProcessor(self.cookieJar))
|
|
||||||
self.opener.open(self.bot.baseUrl)
|
|
||||||
|
|
||||||
def think_thought(self, thought):
|
|
||||||
self.vars['stimulus'] = thought.text
|
|
||||||
data = urlencode(self.vars)
|
|
||||||
data_to_digest = data[9:self.bot.endIndex]
|
|
||||||
data_digest = hashlib.md5(data_to_digest.encode('utf-8')).hexdigest()
|
|
||||||
data = data + '&icognocheck=' + data_digest
|
|
||||||
url_response = self.opener.open(self.bot.serviceUrl, data.encode('utf-8'))
|
|
||||||
response = str(url_response.read())
|
|
||||||
response_values = re.split(r'\\r|\r', response)
|
|
||||||
#self.vars['??'] = _utils_string_at_index(response_values, 0)
|
|
||||||
self.vars['sessionid'] = _utils_string_at_index(response_values, 1)
|
|
||||||
self.vars['logurl'] = _utils_string_at_index(response_values, 2)
|
|
||||||
self.vars['vText8'] = _utils_string_at_index(response_values, 3)
|
|
||||||
self.vars['vText7'] = _utils_string_at_index(response_values, 4)
|
|
||||||
self.vars['vText6'] = _utils_string_at_index(response_values, 5)
|
|
||||||
self.vars['vText5'] = _utils_string_at_index(response_values, 6)
|
|
||||||
self.vars['vText4'] = _utils_string_at_index(response_values, 7)
|
|
||||||
self.vars['vText3'] = _utils_string_at_index(response_values, 8)
|
|
||||||
self.vars['vText2'] = _utils_string_at_index(response_values, 9)
|
|
||||||
self.vars['prevref'] = _utils_string_at_index(response_values, 10)
|
|
||||||
#self.vars['??'] = _utils_string_at_index(response_values, 11)
|
|
||||||
self.vars['emotionalhistory'] = _utils_string_at_index(response_values, 12)
|
|
||||||
self.vars['ttsLocMP3'] = _utils_string_at_index(response_values, 13)
|
|
||||||
self.vars['ttsLocTXT'] = _utils_string_at_index(response_values, 14)
|
|
||||||
self.vars['ttsLocTXT3'] = _utils_string_at_index(response_values, 15)
|
|
||||||
self.vars['ttsText'] = _utils_string_at_index(response_values, 16)
|
|
||||||
self.vars['lineRef'] = _utils_string_at_index(response_values, 17)
|
|
||||||
self.vars['lineURL'] = _utils_string_at_index(response_values, 18)
|
|
||||||
self.vars['linePOST'] = _utils_string_at_index(response_values, 19)
|
|
||||||
self.vars['lineChoices'] = _utils_string_at_index(response_values, 20)
|
|
||||||
self.vars['lineChoicesAbbrev'] = _utils_string_at_index(response_values, 21)
|
|
||||||
self.vars['typingData'] = _utils_string_at_index(response_values, 22)
|
|
||||||
self.vars['divert'] = _utils_string_at_index(response_values, 23)
|
|
||||||
response_thought = ChatterBotThought()
|
|
||||||
response_thought.text = _utils_string_at_index(response_values, 16)
|
|
||||||
return response_thought
|
|
||||||
|
|
||||||
#################################################
|
|
||||||
# Pandorabots impl
|
|
||||||
#################################################
|
|
||||||
|
|
||||||
class _Pandorabots(ChatterBot):
|
|
||||||
|
|
||||||
def __init__(self, botid):
|
|
||||||
self.botid = botid
|
|
||||||
|
|
||||||
def create_session(self):
|
|
||||||
return _PandorabotsSession(self)
|
|
||||||
|
|
||||||
class _PandorabotsSession(ChatterBotSession):
|
|
||||||
|
|
||||||
def __init__(self, bot):
|
|
||||||
self.vars = {}
|
|
||||||
self.vars['botid'] = bot.botid
|
|
||||||
self.vars['custid'] = uuid.uuid1()
|
|
||||||
|
|
||||||
def think_thought(self, thought):
|
|
||||||
self.vars['input'] = thought.text
|
|
||||||
data = urlencode(self.vars)
|
|
||||||
url_response = urlopen('http://www.pandorabots.com/pandora/talk-xml', data)
|
|
||||||
response = url_response.read()
|
|
||||||
response_dom = xml.dom.minidom.parseString(response)
|
|
||||||
response_thought = ChatterBotThought()
|
|
||||||
that_elements = response_dom.getElementsByTagName('that')
|
|
||||||
if that_elements is None or len(that_elements) == 0 or that_elements[0] is None:
|
|
||||||
return ''
|
|
||||||
that_elements_child_nodes = that_elements[0].childNodes
|
|
||||||
if that_elements_child_nodes is None or len(that_elements_child_nodes) == 0 or that_elements_child_nodes[0] is None:
|
|
||||||
return ''
|
|
||||||
that_elements_child_nodes_data = that_elements_child_nodes[0].data
|
|
||||||
if that_elements_child_nodes_data is None:
|
|
||||||
return ''
|
|
||||||
response_thought.text = that_elements_child_nodes_data.strip()
|
|
||||||
return response_thought
|
|
||||||
|
|
||||||
#################################################
|
|
||||||
# Utils
|
|
||||||
#################################################
|
|
||||||
|
|
||||||
def _utils_string_at_index(strings, index):
|
|
||||||
if len(strings) > index:
|
|
||||||
return strings[index]
|
|
||||||
else:
|
|
||||||
return ''
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
rm -rf ~/.local/share/profanity/plugins/*
|
|
||||||
|
|
||||||
cp ascii.py ~/.local/share/profanity/plugins/.
|
|
||||||
cp syscmd.py ~/.local/share/profanity/plugins/.
|
|
||||||
cp paste.py ~/.local/share/profanity/plugins/.
|
|
||||||
cp browser.py ~/.local/share/profanity/plugins/.
|
|
||||||
cp platform-info.py ~/.local/share/profanity/plugins/.
|
|
||||||
cp say.py ~/.local/share/profanity/plugins/.
|
|
||||||
cp whoami.py ~/.local/share/profanity/plugins/.
|
|
||||||
cp wikipedia-prof.py ~/.local/share/profanity/plugins/.
|
|
||||||
cp clients.py ~/.local/share/profanity/plugins/.
|
|
||||||
cp tests/python-test.py ~/.local/share/profanity/plugins/.
|
|
||||||
|
|
||||||
cd pid
|
|
||||||
make clean
|
|
||||||
make
|
|
||||||
cp pid.so ~/.local/share/profanity/plugins/.
|
|
||||||
cd ..
|
|
||||||
|
|
||||||
cd tests/test-c-plugin
|
|
||||||
make clean
|
|
||||||
make
|
|
||||||
cp test-c-plugin.so ~/.local/share/profanity/plugins/.
|
|
||||||
cd ../..
|
|
||||||
|
|
||||||
|
|
||||||
26
emoticons.py
26
emoticons.py
@@ -1,26 +0,0 @@
|
|||||||
"""
|
|
||||||
Convert smileys ( :) :( etc) to the Unicode character representation
|
|
||||||
"""
|
|
||||||
|
|
||||||
import prof
|
|
||||||
|
|
||||||
|
|
||||||
def _emote(input_str):
|
|
||||||
result = input_str
|
|
||||||
result = result.replace(":-)", u'\u263a'.encode("utf-8"))
|
|
||||||
result = result.replace(":)", u'\u263a'.encode("utf-8"))
|
|
||||||
result = result.replace(":-(", u'\u2639'.encode("utf-8"))
|
|
||||||
result = result.replace(":(", u'\u2639'.encode("utf-8"))
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def prof_pre_chat_message_display(jid, message):
|
|
||||||
return _emote(message)
|
|
||||||
|
|
||||||
|
|
||||||
def prof_pre_room_message_display(room, nick, message):
|
|
||||||
return _emote(message)
|
|
||||||
|
|
||||||
|
|
||||||
def prof_pre_priv_message_display(room, nick, message):
|
|
||||||
return _emote(message)
|
|
||||||
531
jenkins.py
531
jenkins.py
@@ -1,531 +0,0 @@
|
|||||||
"""
|
|
||||||
Manage jenkins jobs
|
|
||||||
|
|
||||||
Prerequisites:
|
|
||||||
The jenkinsapi module is required https://pypi.python.org/pypi/jenkinsapi
|
|
||||||
To install the module using pip:
|
|
||||||
sudo pip install jenkinsapi
|
|
||||||
|
|
||||||
The plugin polls the jenkins server at 'jenkins_url' every 'jenkins_poll_interval' seconds.
|
|
||||||
|
|
||||||
The results are checked by profanity every 'prof_cb_interval'.
|
|
||||||
New failures are reported in the jenkins window, and a desktop notification is sent.
|
|
||||||
|
|
||||||
The 'prof_remind_interval' specifies the time between reminder notifications of broken builds
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
import prof
|
|
||||||
import os
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
import webbrowser
|
|
||||||
import urllib2
|
|
||||||
import base64
|
|
||||||
import jenkinsapi
|
|
||||||
from jenkinsapi.jenkins import Jenkins
|
|
||||||
|
|
||||||
# Settings
|
|
||||||
jenkins_url = "http://localhost:8080"
|
|
||||||
username = None
|
|
||||||
password = None
|
|
||||||
jenkins_poll_interval = 5
|
|
||||||
prof_cb_interval = 5
|
|
||||||
prof_remind_interval = 10
|
|
||||||
enable_notify = True
|
|
||||||
enable_remind = True
|
|
||||||
|
|
||||||
# Global state
|
|
||||||
last_state = {}
|
|
||||||
STATE_SUCCESS = "SUCCESS"
|
|
||||||
STATE_UNSTABLE = "UNSTABLE"
|
|
||||||
STATE_FAILURE = "FAILURE"
|
|
||||||
STATE_QUEUED = "QUEUED"
|
|
||||||
STATE_RUNNING = "RUNNING"
|
|
||||||
STATE_NOBUILDS = "NOBUILDS"
|
|
||||||
STATE_UNKNOWN = "UNKNOWN"
|
|
||||||
|
|
||||||
win_tag = "Jenkins"
|
|
||||||
|
|
||||||
poll_fail = False
|
|
||||||
poll_fail_message = None
|
|
||||||
|
|
||||||
job_list = None
|
|
||||||
changes_list = None
|
|
||||||
|
|
||||||
|
|
||||||
def _help():
|
|
||||||
prof.win_show(win_tag, "Commands:")
|
|
||||||
prof.win_show(win_tag, " /jenkins help - Show this help")
|
|
||||||
prof.win_show(win_tag, " /jenkins jobs - List all jobs")
|
|
||||||
prof.win_show(win_tag, " /jenkins failing - List all failing jobs")
|
|
||||||
prof.win_show(win_tag, " /jenkins passing - List all passing jobs")
|
|
||||||
prof.win_show(win_tag, " /jenkins unstable - List all unstable jobs")
|
|
||||||
prof.win_show(win_tag, " /jenkins build [job] - Trigger build for job")
|
|
||||||
prof.win_show(win_tag, " /jenkins open [job] - Open job in browser")
|
|
||||||
prof.win_show(win_tag, " /jenkins log [job] - Show the latest build log")
|
|
||||||
prof.win_show(win_tag, " /jenkins remind on|off - Enable/disable reminder notifications")
|
|
||||||
prof.win_show(win_tag, " /jenkins notify on|off - Enable/disable build notifications")
|
|
||||||
prof.win_show(win_tag, " /jenkins settings - Show current settings")
|
|
||||||
|
|
||||||
|
|
||||||
def _settings():
|
|
||||||
prof.win_show(win_tag, "Jenkins settings:")
|
|
||||||
prof.win_show(win_tag, " Jenkins URL : " + jenkins_url)
|
|
||||||
prof.win_show(win_tag, " Jenkins poll interval : " + str(jenkins_poll_interval) + " seconds")
|
|
||||||
prof.win_show(win_tag, " Profanity update interval : " + str(prof_cb_interval) + " seconds")
|
|
||||||
prof.win_show(win_tag, " Reminder interval : " + str(prof_remind_interval) + " seconds")
|
|
||||||
prof.win_show(win_tag, " Notifications enabled : " + str(enable_notify))
|
|
||||||
prof.win_show(win_tag, " Reminders enabled : " + str(enable_remind))
|
|
||||||
|
|
||||||
|
|
||||||
def _safe_remove(jobname, state):
|
|
||||||
if jobname in last_state[state]:
|
|
||||||
last_state[state].remove(jobname)
|
|
||||||
|
|
||||||
|
|
||||||
def _set_state(jobname, state):
|
|
||||||
if not jobname in last_state[state]:
|
|
||||||
_safe_remove(jobname, STATE_SUCCESS)
|
|
||||||
_safe_remove(jobname, STATE_UNSTABLE)
|
|
||||||
_safe_remove(jobname, STATE_FAILURE)
|
|
||||||
_safe_remove(jobname, STATE_QUEUED)
|
|
||||||
_safe_remove(jobname, STATE_RUNNING)
|
|
||||||
_safe_remove(jobname, STATE_NOBUILDS)
|
|
||||||
_safe_remove(jobname, STATE_UNKNOWN)
|
|
||||||
last_state[state].append(jobname)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def _open_job_url(url):
|
|
||||||
savout = os.dup(1)
|
|
||||||
saverr = os.dup(2)
|
|
||||||
os.close(1)
|
|
||||||
os.close(2)
|
|
||||||
os.open(os.devnull, os.O_RDWR)
|
|
||||||
try:
|
|
||||||
webbrowser.open(url, new=2)
|
|
||||||
finally:
|
|
||||||
os.dup2(savout, 1)
|
|
||||||
os.dup2(saverr, 2)
|
|
||||||
|
|
||||||
|
|
||||||
class JobList():
|
|
||||||
def __init__(self):
|
|
||||||
self.jobs = []
|
|
||||||
|
|
||||||
def add_job(self, name, build_number, state):
|
|
||||||
self.jobs.append((name, build_number, state))
|
|
||||||
|
|
||||||
def get_jobs(self, in_state=None):
|
|
||||||
if not in_state:
|
|
||||||
return self.jobs
|
|
||||||
else:
|
|
||||||
result = []
|
|
||||||
for name, build_number, state in self.jobs:
|
|
||||||
if state == in_state:
|
|
||||||
result.append((name, build_number, state))
|
|
||||||
return result
|
|
||||||
|
|
||||||
def get_job(self, jobname):
|
|
||||||
for name, build_number, state in self.jobs:
|
|
||||||
if name == jobname:
|
|
||||||
return name, build_number
|
|
||||||
return None
|
|
||||||
|
|
||||||
def contains_job(self, jobname):
|
|
||||||
for name, build_number, state in self.jobs:
|
|
||||||
if name == jobname:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def num_in_state(self, given_state):
|
|
||||||
count = 0
|
|
||||||
for name, build_number, state in self.jobs:
|
|
||||||
if state == given_state:
|
|
||||||
count = count + 1
|
|
||||||
return count
|
|
||||||
|
|
||||||
|
|
||||||
class JobUpdates():
|
|
||||||
def __init__(self):
|
|
||||||
self.states = {}
|
|
||||||
self.states[STATE_FAILURE] = []
|
|
||||||
self.states[STATE_SUCCESS] = []
|
|
||||||
self.states[STATE_UNSTABLE] = []
|
|
||||||
self.states[STATE_QUEUED] = []
|
|
||||||
self.states[STATE_RUNNING] = []
|
|
||||||
|
|
||||||
def add_update(self, state, name, build_number=None):
|
|
||||||
if build_number:
|
|
||||||
self.states[state].append((name, build_number))
|
|
||||||
else:
|
|
||||||
self.states[state].append(name)
|
|
||||||
|
|
||||||
def get_in_state(self, state):
|
|
||||||
return self.states[state]
|
|
||||||
|
|
||||||
|
|
||||||
def _process_build(name, build, new_job_list, new_changes_list):
|
|
||||||
if build.get_status() == STATE_FAILURE:
|
|
||||||
new_job_list.add_job(name, build.get_number(), STATE_FAILURE)
|
|
||||||
changed = _set_state(name, STATE_FAILURE)
|
|
||||||
if changed:
|
|
||||||
new_changes_list.add_update(STATE_FAILURE, name, build.get_number())
|
|
||||||
elif build.get_status() == STATE_SUCCESS:
|
|
||||||
new_job_list.add_job(name, build.get_number(), STATE_SUCCESS)
|
|
||||||
changed = _set_state(name, STATE_SUCCESS)
|
|
||||||
if changed:
|
|
||||||
new_changes_list.add_update(STATE_SUCCESS, name, build.get_number())
|
|
||||||
elif build.get_status() == STATE_UNSTABLE:
|
|
||||||
new_job_list.add_job(name, build.get_number(), STATE_UNSTABLE)
|
|
||||||
changed = _set_state(name, STATE_UNSTABLE)
|
|
||||||
if changed:
|
|
||||||
new_changes_list.add_update(STATE_UNSTABLE, name, build.get_number())
|
|
||||||
|
|
||||||
|
|
||||||
def _process_queued_or_running(name, job, new_job_list, new_changes_list):
|
|
||||||
if job.is_queued():
|
|
||||||
new_job_list.add_job(name, None, STATE_QUEUED)
|
|
||||||
changed = _set_state(name, STATE_QUEUED)
|
|
||||||
if changed:
|
|
||||||
new_changes_list.add_update(STATE_QUEUED, name)
|
|
||||||
elif job.is_running():
|
|
||||||
new_job_list.add_job(name, None, STATE_RUNNING)
|
|
||||||
changed = _set_state(name, STATE_RUNNING)
|
|
||||||
if changed:
|
|
||||||
new_changes_list.add_update(STATE_RUNNING, name)
|
|
||||||
|
|
||||||
|
|
||||||
def _jenkins_poll():
|
|
||||||
global poll_fail
|
|
||||||
global poll_fail_message
|
|
||||||
global job_list
|
|
||||||
global changes_list
|
|
||||||
|
|
||||||
job_ac = []
|
|
||||||
|
|
||||||
while True:
|
|
||||||
time.sleep(jenkins_poll_interval)
|
|
||||||
try:
|
|
||||||
j = Jenkins(jenkins_url, username, password)
|
|
||||||
except Exception, e:
|
|
||||||
poll_fail = True
|
|
||||||
poll_fail_message = str(e)
|
|
||||||
else:
|
|
||||||
poll_fail = False
|
|
||||||
poll_fail_message = None
|
|
||||||
new_job_list = JobList()
|
|
||||||
new_changes_list = JobUpdates()
|
|
||||||
for name, job in j.get_jobs():
|
|
||||||
if not job.is_queued_or_running():
|
|
||||||
build = job.get_last_build_or_none()
|
|
||||||
if build:
|
|
||||||
_process_build(name, build, new_job_list, new_changes_list)
|
|
||||||
else:
|
|
||||||
new_job_list.add_job(name, None, STATE_NOBUILDS)
|
|
||||||
else:
|
|
||||||
_process_queued_or_running(name, job, new_job_list, new_changes_list)
|
|
||||||
if not job_list:
|
|
||||||
job_ac.append(name)
|
|
||||||
|
|
||||||
if not job_list:
|
|
||||||
prof.completer_add("/jenkins build", job_ac)
|
|
||||||
prof.completer_add("/jenkins open", job_ac)
|
|
||||||
prof.completer_add("/jenkins log", job_ac)
|
|
||||||
|
|
||||||
job_list = new_job_list
|
|
||||||
changes_list = new_changes_list
|
|
||||||
|
|
||||||
|
|
||||||
def _prof_callback():
|
|
||||||
global changes_list
|
|
||||||
if poll_fail:
|
|
||||||
if not prof.win_exists(win_tag):
|
|
||||||
prof.win_create(win_tag, _handle_input)
|
|
||||||
prof.win_show(win_tag, "Could not connect to jenkins, see the logs.")
|
|
||||||
if poll_fail_message:
|
|
||||||
prof.log_warning("Jenkins poll failed: " + str(poll_fail_message))
|
|
||||||
else:
|
|
||||||
prof.log_warning("Jenkins poll failed")
|
|
||||||
elif changes_list:
|
|
||||||
for name in changes_list.get_in_state(STATE_QUEUED):
|
|
||||||
if not prof.win_exists(win_tag):
|
|
||||||
prof.win_create(win_tag, _handle_input)
|
|
||||||
prof.win_show_themed(win_tag, None, None, "cyan", name + " " + STATE_QUEUED)
|
|
||||||
for name in changes_list.get_in_state(STATE_RUNNING):
|
|
||||||
if not prof.win_exists(win_tag):
|
|
||||||
prof.win_create(win_tag, _handle_input)
|
|
||||||
prof.win_show_themed(win_tag, None, None, "cyan", name + " " + STATE_RUNNING)
|
|
||||||
for name, build_number in changes_list.get_in_state(STATE_SUCCESS):
|
|
||||||
if not prof.win_exists(win_tag):
|
|
||||||
prof.win_create(win_tag, _handle_input)
|
|
||||||
prof.win_show_themed(win_tag, None, None, "green", name + " #" + str(build_number) + " " + STATE_SUCCESS)
|
|
||||||
if enable_notify:
|
|
||||||
prof.notify(name + " " + STATE_SUCCESS, 5000, "Jenkins")
|
|
||||||
for name, build_number in changes_list.get_in_state(STATE_UNSTABLE):
|
|
||||||
if not prof.win_exists(win_tag):
|
|
||||||
prof.win_create(win_tag, _handle_input)
|
|
||||||
prof.win_show_themed(win_tag, None, None, "yellow", name + " #" + str(build_number) + " " + STATE_UNSTABLE)
|
|
||||||
if enable_notify:
|
|
||||||
prof.notify(name + " " + STATE_UNSTABLE, 5000, "Jenkins")
|
|
||||||
for name, build_number in changes_list.get_in_state(STATE_FAILURE):
|
|
||||||
if not prof.win_exists(win_tag):
|
|
||||||
prof.win_create(win_tag, _handle_input)
|
|
||||||
prof.win_show_themed(win_tag, None, None, "red", name + " #" + str(build_number) + " " + STATE_FAILURE)
|
|
||||||
if enable_notify:
|
|
||||||
prof.notify(name + " " + STATE_FAILURE, 5000, "Jenkins")
|
|
||||||
|
|
||||||
changes_list = None
|
|
||||||
|
|
||||||
|
|
||||||
def _handle_input(win, line):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def _list_jobs(jobs):
|
|
||||||
for name, build_number, state in jobs:
|
|
||||||
if state == STATE_SUCCESS:
|
|
||||||
prof.win_show_themed(win_tag, None, None, "green", " " + name + " #" + str(build_number) + " " + STATE_SUCCESS)
|
|
||||||
elif state == STATE_UNSTABLE:
|
|
||||||
prof.win_show_themed(win_tag, None, None, "yellow", " " + name + " #" + str(build_number) + " " + STATE_UNSTABLE)
|
|
||||||
elif state == STATE_FAILURE:
|
|
||||||
prof.win_show_themed(win_tag, None, None, "red", " " + name + " #" + str(build_number) + " " + STATE_FAILURE)
|
|
||||||
elif state == STATE_NOBUILDS:
|
|
||||||
prof.win_show(win_tag, " " + name + ", no builds")
|
|
||||||
else:
|
|
||||||
prof.win_show_themed(win_tag, None, None, "cyan", " " + name + " " + state)
|
|
||||||
|
|
||||||
|
|
||||||
def _build_job(job):
|
|
||||||
try:
|
|
||||||
request = urllib2.Request(jenkins_url + "/job/" + job + "/build");
|
|
||||||
if username:
|
|
||||||
basicauth = base64.encodestring("%s:%s" %(username, password)).replace("\n", "")
|
|
||||||
request.add_header("Authorization", "Basic %s" %basicauth);
|
|
||||||
request.add_data("")
|
|
||||||
urllib2.urlopen(request)
|
|
||||||
except Exception, e:
|
|
||||||
prof.win_show(win_tag, "Failed to build " + job + ", see the logs.")
|
|
||||||
prof.log_warning("Failed to build " + job + ": " + str(e))
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "Build request sent for " + job)
|
|
||||||
|
|
||||||
|
|
||||||
def _job_log(job):
|
|
||||||
name = job[0]
|
|
||||||
build_no = job[1]
|
|
||||||
if build_no:
|
|
||||||
try:
|
|
||||||
response = urllib2.urlopen(jenkins_url + "/job/" + name + "/" + str(build_no) + "/consoleText")
|
|
||||||
except Exception, e:
|
|
||||||
prof.win_show(win_tag, "Unable to fetch log for " + name + "#" + str(build_no) + ", see the logs.")
|
|
||||||
prof.log_warning("Unable to fetch log for " + name + "#" + str(build_no) + ": " + str(e))
|
|
||||||
else:
|
|
||||||
log_str = "Log for " + name + " #" + str(build_no) + ":\n" + response.read()
|
|
||||||
prof.win_show(win_tag, log_str)
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No build found for " + name)
|
|
||||||
|
|
||||||
|
|
||||||
def _cmd_jenkins(cmd=None, arg=None):
|
|
||||||
global enable_remind
|
|
||||||
global enable_notify
|
|
||||||
|
|
||||||
if not prof.win_exists(win_tag):
|
|
||||||
prof.win_create(win_tag, _handle_input)
|
|
||||||
|
|
||||||
prof.win_focus(win_tag)
|
|
||||||
|
|
||||||
if cmd == "jobs":
|
|
||||||
if job_list and job_list.get_jobs():
|
|
||||||
prof.win_show(win_tag, "Jobs:")
|
|
||||||
_list_jobs(job_list.get_jobs())
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No job data yet.")
|
|
||||||
elif cmd == "failing":
|
|
||||||
if job_list:
|
|
||||||
jobs_in_state = job_list.get_jobs(STATE_FAILURE)
|
|
||||||
if jobs_in_state:
|
|
||||||
prof.win_show(win_tag, "Failing jobs:")
|
|
||||||
_list_jobs(jobs_in_state)
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No failing jobs.")
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No job data yet.")
|
|
||||||
elif cmd == "passing":
|
|
||||||
if job_list:
|
|
||||||
jobs_in_state = job_list.get_jobs(STATE_SUCCESS)
|
|
||||||
if jobs_in_state:
|
|
||||||
prof.win_show(win_tag, "Passing jobs:")
|
|
||||||
_list_jobs(jobs_in_state)
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No passing jobs.")
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No job data yet.")
|
|
||||||
elif cmd == "unstable":
|
|
||||||
if job_list:
|
|
||||||
jobs_in_state = job_list.get_jobs(STATE_UNSTABLE)
|
|
||||||
if jobs_in_state:
|
|
||||||
prof.win_show(win_tag, "Unstable jobs:")
|
|
||||||
_list_jobs(jobs_in_state)
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No unstable jobs.")
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No job data yet.")
|
|
||||||
elif cmd == "build":
|
|
||||||
if not arg:
|
|
||||||
prof.win_show(win_tag, "You must supply a job argument.")
|
|
||||||
elif job_list and job_list.contains_job(arg):
|
|
||||||
_build_job(arg)
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No such job: " + arg)
|
|
||||||
elif cmd == "open":
|
|
||||||
if not arg:
|
|
||||||
prof.win_show(win_tag, "You must supply a job argument.")
|
|
||||||
elif job_list and job_list.contains_job(arg):
|
|
||||||
_open_job_url(jenkins_url + "/job/" + arg)
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No such job: " + arg)
|
|
||||||
elif cmd == "remind":
|
|
||||||
if not arg:
|
|
||||||
prof.win_show(win_tag, "You must specify either 'on' or 'off'.")
|
|
||||||
elif arg == "on":
|
|
||||||
enable_remind = True
|
|
||||||
prof.win_show(win_tag, "Reminder notifications enabled.")
|
|
||||||
elif arg == "off":
|
|
||||||
enable_remind = False
|
|
||||||
prof.win_show(win_tag, "Reminder notifications disabled.")
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "You must specify either 'on' or 'off'.")
|
|
||||||
elif cmd == "notify":
|
|
||||||
if not arg:
|
|
||||||
prof.win_show(win_tag, "You must specify either 'on' or 'off'.")
|
|
||||||
elif arg == "on":
|
|
||||||
enable_notify = True
|
|
||||||
prof.win_show(win_tag, "Build notifications enabled.")
|
|
||||||
elif arg == "off":
|
|
||||||
enable_notify = False
|
|
||||||
prof.win_show(win_tag, "Build notifications disabled.")
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "You must specify either 'on' or 'off'.")
|
|
||||||
elif cmd == "settings":
|
|
||||||
_settings()
|
|
||||||
elif cmd == "help":
|
|
||||||
_help()
|
|
||||||
elif cmd == "log":
|
|
||||||
if not arg:
|
|
||||||
prof.win_show(win_tag, "You must specify a job.")
|
|
||||||
else:
|
|
||||||
job = job_list.get_job(arg)
|
|
||||||
if job:
|
|
||||||
_job_log(job)
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "No job found: " + arg)
|
|
||||||
else:
|
|
||||||
prof.win_show(win_tag, "Unknown command.")
|
|
||||||
|
|
||||||
|
|
||||||
def _remind():
|
|
||||||
if enable_remind and job_list:
|
|
||||||
notify_string = ""
|
|
||||||
failing = job_list.num_in_state(STATE_FAILURE)
|
|
||||||
unstable = job_list.num_in_state(STATE_UNSTABLE)
|
|
||||||
|
|
||||||
if failing == 1:
|
|
||||||
notify_string = notify_string + "1 failing build"
|
|
||||||
if failing > 1:
|
|
||||||
notify_string = notify_string + str(failing) + " failing builds"
|
|
||||||
|
|
||||||
if failing > 0 and unstable > 0:
|
|
||||||
notify_string = notify_string + "\n"
|
|
||||||
|
|
||||||
if unstable == 1:
|
|
||||||
notify_string = notify_string + "1 unstable build"
|
|
||||||
if unstable > 1:
|
|
||||||
notify_string = notify_string + str(unstable) + " unstable builds"
|
|
||||||
|
|
||||||
if not notify_string == "":
|
|
||||||
prof.notify(notify_string, 5000, "Jenkins")
|
|
||||||
|
|
||||||
|
|
||||||
def prof_init(version, status, account_name, fulljid):
|
|
||||||
last_state[STATE_SUCCESS] = []
|
|
||||||
last_state[STATE_UNSTABLE] = []
|
|
||||||
last_state[STATE_FAILURE] = []
|
|
||||||
last_state[STATE_QUEUED] = []
|
|
||||||
last_state[STATE_RUNNING] = []
|
|
||||||
last_state[STATE_NOBUILDS] = []
|
|
||||||
last_state[STATE_UNKNOWN] = []
|
|
||||||
|
|
||||||
jenkins_t = threading.Thread(target=_jenkins_poll)
|
|
||||||
jenkins_t.daemon = True;
|
|
||||||
jenkins_t.start()
|
|
||||||
|
|
||||||
prof.register_timed(_prof_callback, prof_cb_interval)
|
|
||||||
prof.register_timed(_remind, prof_remind_interval)
|
|
||||||
|
|
||||||
prof.completer_add(
|
|
||||||
"/jenkins", [
|
|
||||||
"help",
|
|
||||||
"jobs",
|
|
||||||
"failing",
|
|
||||||
"passing",
|
|
||||||
"unstable",
|
|
||||||
"build",
|
|
||||||
"open",
|
|
||||||
"log",
|
|
||||||
"remind",
|
|
||||||
"notify",
|
|
||||||
"settings"
|
|
||||||
]
|
|
||||||
);
|
|
||||||
prof.completer_add(
|
|
||||||
"/jenkins remind", [
|
|
||||||
"on",
|
|
||||||
"off"
|
|
||||||
]
|
|
||||||
);
|
|
||||||
prof.completer_add(
|
|
||||||
"/jenkins notify", [
|
|
||||||
"on",
|
|
||||||
"off"
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
synopsis = [
|
|
||||||
"/jenkins jobs|failing|passing|unstable",
|
|
||||||
"/jenkins build <job>",
|
|
||||||
"/jenkins open <job>",
|
|
||||||
"/jenkins log <job>",
|
|
||||||
"/jenkins remind on|off",
|
|
||||||
"/jenkins notify on|off",
|
|
||||||
"/jenkins settings"
|
|
||||||
]
|
|
||||||
description = "Monitor, run and view Jenkins jobs."
|
|
||||||
args = [
|
|
||||||
[ "jobs", "List all jobs" ],
|
|
||||||
[ "failing", "List all failing jobs" ],
|
|
||||||
[ "passing", "List all passing jobs" ],
|
|
||||||
[ "unstable", "List all unstable jobs" ],
|
|
||||||
[ "build <job>", "Trigger build for job" ],
|
|
||||||
[ "open <job>", "Open job in browser" ],
|
|
||||||
[ "log <job>", "Show the latest build log for job" ],
|
|
||||||
[ "remind on|off", "Enable/disable reminder notifications" ],
|
|
||||||
[ "notify on|off", "Enable/disable build notifications" ],
|
|
||||||
[ "settings", "Show current settings" ]
|
|
||||||
]
|
|
||||||
examples = [
|
|
||||||
"/kenkins failing",
|
|
||||||
"/kenkins build stabber-build",
|
|
||||||
"/kenkins remind off"
|
|
||||||
]
|
|
||||||
|
|
||||||
prof.register_command("/jenkins", 0, 2, synopsis, description, args, examples, _cmd_jenkins)
|
|
||||||
|
|
||||||
|
|
||||||
def prof_on_start():
|
|
||||||
prof.win_create(win_tag, _handle_input)
|
|
||||||
prof.win_show(win_tag, "Jenkins plugin started.")
|
|
||||||
24
paste.py
24
paste.py
@@ -1,24 +0,0 @@
|
|||||||
"""
|
|
||||||
Paste the contents of the clipboard when in a chat or room window.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import prof
|
|
||||||
import sys
|
|
||||||
import Tkinter as tk
|
|
||||||
|
|
||||||
|
|
||||||
def _cmd_paste():
|
|
||||||
root = tk.Tk(baseName="")
|
|
||||||
root.withdraw()
|
|
||||||
result = root.clipboard_get()
|
|
||||||
prof.send_line(u'\u000A' + result)
|
|
||||||
|
|
||||||
|
|
||||||
def prof_init(version, status, account_name, fulljid):
|
|
||||||
synopsis = [
|
|
||||||
"/paste"
|
|
||||||
]
|
|
||||||
description = "Paste contents of clipboard."
|
|
||||||
args = []
|
|
||||||
examples = []
|
|
||||||
prof.register_command("/paste", 0, 0, synopsis, description, args, examples, _cmd_paste)
|
|
||||||
276
src/ai.py
Normal file
276
src/ai.py
Normal file
@@ -0,0 +1,276 @@
|
|||||||
|
"""AI Chat Plugin for CProof XMPP Client
|
||||||
|
|
||||||
|
This plugin enables interaction with AI models via a dedicated chat window using the
|
||||||
|
LiteLLM library, supporting providers like xAI (Grok) and OpenAI. Commands allow setting
|
||||||
|
default models, API tokens, starting chats, clearing windows, and correcting messages.
|
||||||
|
|
||||||
|
- Requires the `litellm` library (`pip install litellm`).
|
||||||
|
- Configure API tokens with zero-data-retention agreements for maximum privacy.
|
||||||
|
- Use models like xAI's Grok for minimal data retention.
|
||||||
|
- Chat history is not persisted locally beyond the active session.
|
||||||
|
|
||||||
|
See Also:
|
||||||
|
- LiteLLM documentation: https://docs.litellm.ai/docs/
|
||||||
|
- xAI API: https://x.ai/api
|
||||||
|
"""
|
||||||
|
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
import litellm
|
||||||
|
import prof
|
||||||
|
|
||||||
|
from typing import Callable, Dict, List, Optional, Tuple
|
||||||
|
|
||||||
|
# Global settings
|
||||||
|
DEFAULT_MODEL_KEY = "default_model" # Changed to avoid hardcoding model
|
||||||
|
TOKEN_KEY = "ai_tokens"
|
||||||
|
CHAT_WIN_ID: Optional[int] = None
|
||||||
|
# Global message history: {win_id: [{"role": "user"|"assistant", "content": str}, ...]}
|
||||||
|
CHAT_HISTORY: Dict[str, List[Dict[str, str]]] = {}
|
||||||
|
# Output file for safe display
|
||||||
|
OUTPUT_FILE = "/tmp/ai_output.txt"
|
||||||
|
|
||||||
|
FILE_LOCK = threading.Lock()
|
||||||
|
|
||||||
|
# Privacy settings for LiteLLM
|
||||||
|
litellm.drop_params = True
|
||||||
|
litellm.set_verbose = False
|
||||||
|
|
||||||
|
# Disable printing in the console to avoid breaking profanity's outline
|
||||||
|
litellm.suppress_debug_info = True
|
||||||
|
|
||||||
|
|
||||||
|
def _get_tokens() -> Dict[str, str]:
|
||||||
|
"""Retrieve tokens from settings as a dictionary."""
|
||||||
|
tokens: Dict[str, str] = {}
|
||||||
|
token_strings = prof.settings_string_list_get("ai_plugin", TOKEN_KEY)
|
||||||
|
if not token_strings:
|
||||||
|
return tokens
|
||||||
|
for ts in token_strings:
|
||||||
|
if ":" in ts:
|
||||||
|
company, token = ts.split(":", 1)
|
||||||
|
tokens[company] = token
|
||||||
|
return tokens
|
||||||
|
|
||||||
|
|
||||||
|
def _save_tokens(tokens: Dict[str, str]) -> None:
|
||||||
|
"""Save tokens to settings as a list of 'company:token' strings."""
|
||||||
|
prof.settings_string_list_clear("ai_plugin", TOKEN_KEY)
|
||||||
|
for company, token in tokens.items():
|
||||||
|
prof.settings_string_list_add("ai_plugin", TOKEN_KEY, f"{company}:{token}")
|
||||||
|
|
||||||
|
|
||||||
|
def display_settings() -> None:
|
||||||
|
"""Show the current default model and registered tokens."""
|
||||||
|
model = get_default_model()
|
||||||
|
tokens = _get_tokens()
|
||||||
|
token_info = ", ".join([f"{company}: {token[:4]}..." for company, token in tokens.items()])
|
||||||
|
prof.cons_show(f"AI Settings: Default Model: {model}, Tokens: {token_info or 'None set'}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_model(model) -> None:
|
||||||
|
"""Set the default model to be used for AI chats."""
|
||||||
|
set_default_model(model)
|
||||||
|
prof.cons_show(f"Default model set to: {model}")
|
||||||
|
|
||||||
|
def run_completion(window_id: str, model: str, history: list, outfile: str, tokens: dict, file_lock) -> None:
|
||||||
|
"""Run AI completion and write response to file."""
|
||||||
|
try:
|
||||||
|
response = litellm.completion(
|
||||||
|
model=model,
|
||||||
|
messages=history,
|
||||||
|
api_key=tokens.get(model.split("/")[0], None),
|
||||||
|
).choices[0].message.content
|
||||||
|
with file_lock:
|
||||||
|
with open(outfile, "a") as f:
|
||||||
|
json.dump({"win_id": window_id, "content": f"AI: {response}"}, f)
|
||||||
|
f.write("\n")
|
||||||
|
except Exception as e:
|
||||||
|
with file_lock:
|
||||||
|
with open(outfile, "a") as f:
|
||||||
|
json.dump({"win_id": window_id, "content": f"Error: {str(e)}"}, f)
|
||||||
|
f.write("\n")
|
||||||
|
|
||||||
|
def handler(win_id: str, message: str) -> None:
|
||||||
|
"""Process messages in a chat window using the model from the window title.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
win_id: Identifier for the chat window, used to extract the model name.
|
||||||
|
message: The user's message to process.
|
||||||
|
"""
|
||||||
|
model = win_id.split(" - ", 2)[1]
|
||||||
|
prof.win_show(win_id, f"Me: {message}")
|
||||||
|
|
||||||
|
# Create a new history list for this call to avoid modifying shared state
|
||||||
|
current_history = CHAT_HISTORY.get(win_id, []) + [{"role": "user", "content": message}]
|
||||||
|
|
||||||
|
thread = threading.Thread(target=run_completion, args=(win_id, model, current_history, OUTPUT_FILE, _get_tokens(), FILE_LOCK))
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
def process_queued_outputs() -> None:
|
||||||
|
"""Process outputs from the file using prof.win_show."""
|
||||||
|
if os.path.exists(OUTPUT_FILE):
|
||||||
|
with open(OUTPUT_FILE, "r") as f:
|
||||||
|
lines = f.readlines()
|
||||||
|
outputs = []
|
||||||
|
for line in lines:
|
||||||
|
if line.strip():
|
||||||
|
try:
|
||||||
|
data = json.loads(line)
|
||||||
|
outputs.append((data["win_id"], data["content"]))
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
pass
|
||||||
|
for win_id, content in outputs:
|
||||||
|
prof.win_show(win_id, content)
|
||||||
|
open(OUTPUT_FILE, "w").close() # truncate the file
|
||||||
|
|
||||||
|
|
||||||
|
def create_chat_window(model: str) -> str:
|
||||||
|
"""Create a new window for AI chat with the specified model."""
|
||||||
|
win_id = f"AI Chat - {model} - {int(time.time())}"
|
||||||
|
prof.win_create(win_id, handler)
|
||||||
|
prof.win_show(win_id, f"Chat started with {model}. Type a message to interact.")
|
||||||
|
prof.win_focus(win_id)
|
||||||
|
return win_id
|
||||||
|
|
||||||
|
|
||||||
|
def start_chat(model: Optional[str] = None) -> None:
|
||||||
|
"""Open a new chat window with the specified or default model."""
|
||||||
|
model = model if model else get_default_model()
|
||||||
|
create_chat_window(model)
|
||||||
|
prof.cons_show(f"Started AI chat with model: {model}")
|
||||||
|
|
||||||
|
|
||||||
|
def set_token(company: str, token: str) -> None:
|
||||||
|
"""Store an API token for a specific company."""
|
||||||
|
tokens = _get_tokens()
|
||||||
|
tokens[company] = token
|
||||||
|
_save_tokens(tokens)
|
||||||
|
prof.cons_show(f"Token set for {company}")
|
||||||
|
|
||||||
|
|
||||||
|
def clear_chat() -> None:
|
||||||
|
"""Notify that the current chat window is cleared."""
|
||||||
|
prof.cons_show("Sorry, current API doesn't support cleaning windows")
|
||||||
|
return
|
||||||
|
win_id = prof.get_current_win()
|
||||||
|
if win_id:
|
||||||
|
prof.win_show(win_id, "Chat cleared.")
|
||||||
|
else:
|
||||||
|
prof.cons_show("No active chat window.")
|
||||||
|
|
||||||
|
|
||||||
|
def correct_message(corrected_text: str) -> None:
|
||||||
|
"""Replace the latest user message in the current window's history and get AI response."""
|
||||||
|
prof.cons_show("Sorry, current API doesn't support correcting messages and getting current window")
|
||||||
|
return
|
||||||
|
# work in progress (get_current_win doesn't work)
|
||||||
|
win_id = prof.get_current_win()
|
||||||
|
if not win_id:
|
||||||
|
prof.cons_show("No active chat window. Use /ai start <model> first.")
|
||||||
|
return
|
||||||
|
title = prof.get_win_title(win_id)
|
||||||
|
if not title or not title.startswith("AI Chat - "):
|
||||||
|
prof.cons_show("Invalid chat window. Use /ai start <model> to create one.")
|
||||||
|
return
|
||||||
|
model = title.split(" - ", 2)[1]
|
||||||
|
history = CHAT_HISTORY.get(win_id, [])
|
||||||
|
user_messages = [msg for msg in history if msg["role"] == "user"]
|
||||||
|
if not user_messages:
|
||||||
|
prof.cons_show("No user messages in this chat to correct.")
|
||||||
|
return
|
||||||
|
# Replace the latest user message
|
||||||
|
for msg in history[::-1]:
|
||||||
|
if msg["role"] == "user":
|
||||||
|
msg["content"] = corrected_text
|
||||||
|
break
|
||||||
|
handler(win_id, corrected_text)
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_model() -> str:
|
||||||
|
"""Retrieve the default model from settings, defaulting to gpt-5.0."""
|
||||||
|
return prof.settings_string_get("ai_plugin", DEFAULT_MODEL_KEY, "openai/gpt-5.0")
|
||||||
|
|
||||||
|
|
||||||
|
def set_default_model(model: str) -> None:
|
||||||
|
"""Save the default model to settings."""
|
||||||
|
prof.settings_string_set("ai_plugin", DEFAULT_MODEL_KEY, model)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_ai(*args: Tuple[Optional[str], ...]) -> None:
|
||||||
|
"""Handle /ai commands for interacting with AI models.
|
||||||
|
|
||||||
|
Synopsis:
|
||||||
|
/ai
|
||||||
|
/ai set model <model>
|
||||||
|
/ai start [<model>]
|
||||||
|
/ai set token <company> <token>
|
||||||
|
/ai clear
|
||||||
|
/ai correct <message>
|
||||||
|
"""
|
||||||
|
if not args:
|
||||||
|
display_settings()
|
||||||
|
return
|
||||||
|
if args[0] == "set" and len(args) >= 2:
|
||||||
|
if args[1] == "model" and len(args) == 3:
|
||||||
|
set_model(args[2])
|
||||||
|
elif args[1] == "token" and len(args) == 3:
|
||||||
|
try:
|
||||||
|
company, token = args[2].split(" ", 1)
|
||||||
|
set_token(company, token)
|
||||||
|
except ValueError:
|
||||||
|
prof.cons_show("Invalid format, use: /ai set token <company> <token>")
|
||||||
|
else:
|
||||||
|
prof.cons_show("Invalid command, use: /ai set model|token")
|
||||||
|
elif args[0] == "start" and len(args) <= 3:
|
||||||
|
start_chat(args[1] if len(args) == 2 else None)
|
||||||
|
elif args[0] == "clear" and len(args) == 1:
|
||||||
|
clear_chat()
|
||||||
|
elif args[0] == "correct" and len(args) == 3:
|
||||||
|
correct_message(args[2])
|
||||||
|
else:
|
||||||
|
prof.cons_bad_cmd_usage("/ai")
|
||||||
|
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
"""Initialize the AI chat plugin and register commands."""
|
||||||
|
|
||||||
|
synopsis = [
|
||||||
|
"/ai",
|
||||||
|
"/ai set model <model>",
|
||||||
|
"/ai start [<model>]",
|
||||||
|
"/ai set token <company> <token>",
|
||||||
|
"/ai clear",
|
||||||
|
"/ai correct <message>",
|
||||||
|
]
|
||||||
|
description = """Interact with AI models via a chat interface using LiteLLM.
|
||||||
|
You can see the list of available models here: https://models.litellm.ai/"""
|
||||||
|
args = [
|
||||||
|
["", "Display current AI plugin settings"],
|
||||||
|
["set model <model>", "Set the default AI model (e.g., gpt-3.5-turbo)"],
|
||||||
|
["start [<model>]", "Start a new AI chat with the specified or default model"],
|
||||||
|
["set token <company> <token>", "Set an API token for a specific company"],
|
||||||
|
["clear", "Clear the current AI chat window"],
|
||||||
|
["correct <message>", "Correct a message using the current AI model"],
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/ai",
|
||||||
|
"/ai set token openai sk-xxx",
|
||||||
|
"/ai set model gpt-4",
|
||||||
|
"/ai start xai/grok-4",
|
||||||
|
"/ai clear",
|
||||||
|
'/ai correct I has a error',
|
||||||
|
]
|
||||||
|
|
||||||
|
prof.register_command("/ai", 0, 3, synopsis, description, args, examples, _cmd_ai)
|
||||||
|
prof.completer_add("/ai", ["set", "start", "clear", "correct"])
|
||||||
|
prof.completer_add("/ai set", ["model", "token"])
|
||||||
|
prof.completer_add("/ai set model", ["openai/gpt-5", "xai/grok-3-mini"])
|
||||||
|
prof.completer_add("/ai start", ["xai/grok-4", "openai/gpt-4o"])
|
||||||
|
prof.completer_add("/ai set token", ["openai", "xai"])
|
||||||
|
|
||||||
|
prof.register_timed(process_queued_outputs, 1) # 1s interval to process AI message output
|
||||||
549
src/antispam.py
Normal file
549
src/antispam.py
Normal file
@@ -0,0 +1,549 @@
|
|||||||
|
"""
|
||||||
|
Antispam plugin for CProof.
|
||||||
|
|
||||||
|
Asks a question from new contacts to verify their humanity.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
|
import prof
|
||||||
|
import re
|
||||||
|
import datetime
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
_antispam_defaults = {
|
||||||
|
'msg': 'Please, solve the captcha',
|
||||||
|
'question': 'Where a bullet must be lodged in order for rifle to shoot?',
|
||||||
|
'answer': 'Chamber',
|
||||||
|
'donemsg': 'You passed antispam. Congratulations!',
|
||||||
|
'blockmsg': 'You\'ve been blocked. Try again {} minutes later',
|
||||||
|
'errormsg': 'Wrong answer. Please, try again. The question is',
|
||||||
|
'otrmsg': 'Please, turn off the OTR and then send the answer.',
|
||||||
|
'unbanmsg': 'Your ban has been lifted. You can try again.',
|
||||||
|
'maxtries': 5,
|
||||||
|
'blocktime': 5,
|
||||||
|
'debug': 'off',
|
||||||
|
'dry': 'off'
|
||||||
|
}
|
||||||
|
|
||||||
|
_time_format = "%d.%m.%Y %H:%M:%S"
|
||||||
|
|
||||||
|
_roster = []
|
||||||
|
|
||||||
|
_page_limit = 10
|
||||||
|
|
||||||
|
_egg_counter = 0
|
||||||
|
|
||||||
|
_as_settings_strings = ['msg', 'question', 'answer', 'donemsg', 'blockmsg', 'otrmsg', 'errormsg', 'unbanmsg', 'debug', 'dry']
|
||||||
|
_as_settings_ints = {'maxtries': {'min': 2, 'max': 1000}, 'blocktime': {'min': -1, 'max': 100000}}
|
||||||
|
_as_settings = [*_as_settings_strings, *_as_settings_ints]
|
||||||
|
|
||||||
|
|
||||||
|
# Handlers
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
synopsis = [
|
||||||
|
"/antispam on|off",
|
||||||
|
"/antispam settings",
|
||||||
|
*[f"/antispam set {x} <msg>" for x in _as_settings_strings],
|
||||||
|
"/antispam set maxtries <tries>",
|
||||||
|
"/antispam set blocktime <minutes>",
|
||||||
|
"/antispam counter [<page|clear>]",
|
||||||
|
"/antispam history [<page|clear>]",
|
||||||
|
"/antispam blocklist [<page>|add|remove <jid or part of jid>|clear]",
|
||||||
|
"/antispam whitelist [<page>|add|remove <jid or part of jid>|clear]",
|
||||||
|
]
|
||||||
|
description = "Prevents spam messages by asking new contacts questions."
|
||||||
|
args = [
|
||||||
|
[ "set msg <msg>", "Set captcha message" ],
|
||||||
|
[ "set question <msg>", "Set custom captcha question" ],
|
||||||
|
[ "set answer <msg>", "Set answer to captcha question" ],
|
||||||
|
[ "set donemsg <msg>", "Set congratulation message for passing antispam" ],
|
||||||
|
[ "set blockmsg <msg>", "Set message that user is blocked. Use \"{}\" to show amounts of minutes before unlock. Example: You are banned. Unban in {} minutes." ],
|
||||||
|
[ "set otrmsg <msg>", "Set answer in case if unauthorized user tries to initiate OTR session." ],
|
||||||
|
[ "set errormsg <msg>", "Set prefix to answer in case if wrong answer given." ],
|
||||||
|
[ "set unbanmsg <msg>", "Set message given when temporary ban is finished. Set to \"None\" to prevent sending message." ],
|
||||||
|
[ "set maxtries <tries>", "Set maximum amount of tries before ban. Set -1 to make unlimited." ],
|
||||||
|
[ "set blocktime <minutes>", "Set time to block user for. Set -1 to make ban unlimited." ],
|
||||||
|
[ "set debug <on|off>", "Set debug mode on|off." ],
|
||||||
|
[ "set dry <on|off>", "Set dry mode on|off. In dry mode antispam doesn't block messages, mode is needed for debug use." ],
|
||||||
|
[ "counter [<page>|clear]", "Show or clear wrong answer counter" ],
|
||||||
|
[ "history [<page>|clear]", "Show or clear history" ],
|
||||||
|
[ "blocklist [add|remove <jid or part of jid>|clear]", "Show banned users, or add|remove user from ban" ],
|
||||||
|
[ "whitelist [add|remove <jid or part of jid>|clear]", "Whitelist users. Whitelist have priority over bans." ],
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/antispam on",
|
||||||
|
"/antispam set msg Please, solve the captcha.",
|
||||||
|
"/antispam set question 2 + 2? (1984)",
|
||||||
|
"/antispam set answer 5",
|
||||||
|
"/antispam set donemsg You passed antispam. Now your messages are delivered.",
|
||||||
|
"/antispam set blockmsg You've been blocked by antispam. Please, try again later in {} minute(s).",
|
||||||
|
"/antispam set maxtries 5",
|
||||||
|
"/antispam set blocktime 69",
|
||||||
|
"/antispam blocklist clear",
|
||||||
|
"/antispam history 42",
|
||||||
|
]
|
||||||
|
|
||||||
|
prof.register_command("/antispam", 1, 40, synopsis, description, args, examples, _cmd_antispam)
|
||||||
|
|
||||||
|
prof.register_command("/as", 1, 40, _prep_alias(synopsis), description, args, _prep_alias(examples), _cmd_antispam)
|
||||||
|
|
||||||
|
prof.completer_add("/antispam",
|
||||||
|
[ "set", "history", "blocklist", "whitelist" ]
|
||||||
|
)
|
||||||
|
|
||||||
|
prof.completer_add("/antispam set",
|
||||||
|
_as_settings
|
||||||
|
)
|
||||||
|
prof.completer_add("/antispam history",
|
||||||
|
[ 'clear' ]
|
||||||
|
)
|
||||||
|
|
||||||
|
prof.completer_add("/antispam blocklist",
|
||||||
|
[ 'add', 'remove', 'clear' ]
|
||||||
|
)
|
||||||
|
|
||||||
|
prof.completer_add("/antispam whitelist",
|
||||||
|
[ 'add', 'remove', 'clear' ]
|
||||||
|
)
|
||||||
|
|
||||||
|
prof.register_timed(_update_banned_list, 60)
|
||||||
|
|
||||||
|
_force_update_roster((fulljid.split('/')[0] if fulljid else ''))
|
||||||
|
|
||||||
|
prof.cons_show("[AntiSpam] plugin started.")
|
||||||
|
if _is_dry_mode():
|
||||||
|
prof.cons_show("[AntiSpam] WARNING: dry-mode is on, no messages are going to be blocked.")
|
||||||
|
|
||||||
|
def prof_on_message_stanza_send(stanza):
|
||||||
|
body = _parse_tag_content(stanza, 'body')
|
||||||
|
if body and (to := _parse_attr(stanza, 'to').split('/', 1)[0]):
|
||||||
|
if not _is_authorized(to):
|
||||||
|
prof.settings_string_list_add("antispam", "authorized", to)
|
||||||
|
return stanza
|
||||||
|
|
||||||
|
def prof_on_presence_stanza_send(stanza):
|
||||||
|
if _parse_attr(stanza, 'type') == 'subscribe' and (to := _parse_attr(stanza, 'to').split('/', 1)[0]):
|
||||||
|
if not _is_authorized(to):
|
||||||
|
prof.settings_string_list_add("antispam", "authorized", to)
|
||||||
|
return stanza
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_message_stanza_receive(stanza) -> bool:
|
||||||
|
return _antispam_check_wrapper(stanza, 'msg')
|
||||||
|
|
||||||
|
def prof_on_presence_stanza_receive(stanza) -> bool:
|
||||||
|
return _antispam_check_wrapper(stanza, 'presence')
|
||||||
|
|
||||||
|
def prof_on_iq_stanza_receive(stanza) -> bool:
|
||||||
|
if 'jabber:iq:roster' in stanza and 'type="result"' in stanza:
|
||||||
|
_update_roster(stanza)
|
||||||
|
return _antispam_check_wrapper(stanza, 'iq')
|
||||||
|
|
||||||
|
# Custom functions
|
||||||
|
|
||||||
|
def _cmd_antispam(*args):
|
||||||
|
if not len(args):
|
||||||
|
_show_cmd_error()
|
||||||
|
if args[0] == "on":
|
||||||
|
prof.settings_boolean_set("antispam", "enabled", True)
|
||||||
|
prof.cons_show("Antispam is enabled.")
|
||||||
|
return
|
||||||
|
if args[0] == "off":
|
||||||
|
prof.settings_boolean_set("antispam", "enabled", False)
|
||||||
|
prof.cons_show("Antispam is disabled.")
|
||||||
|
return
|
||||||
|
if args[0] == "set":
|
||||||
|
if len(args) < 3:
|
||||||
|
_show_cmd_error('More arguments required')
|
||||||
|
return
|
||||||
|
key = args[1]
|
||||||
|
if key not in _as_settings:
|
||||||
|
_show_cmd_error(f'Wrong setting. You can use only {_as_settings}')
|
||||||
|
return
|
||||||
|
if args[2] == "default":
|
||||||
|
_set_default_values(key)
|
||||||
|
return
|
||||||
|
if _set_values(key, args[2:]):
|
||||||
|
prof.cons_show(f'Antispam setting {key} was successfully changed to "{" ".join(args[2:])}"')
|
||||||
|
else:
|
||||||
|
_show_cmd_error("Something went wrong, setting wasn't changed")
|
||||||
|
return
|
||||||
|
if args[0] == "settings":
|
||||||
|
prof.cons_show("===== Antispam settings =====")
|
||||||
|
for key in _as_settings:
|
||||||
|
value = _get_string_setting(key) if key in _as_settings_strings else _get_int_setting(key)
|
||||||
|
fvalue = f'"{value}"' if key in _as_settings_strings else value
|
||||||
|
prof.cons_show(f'{key} is {fvalue}')
|
||||||
|
return
|
||||||
|
if args[0] in ["counter", "history", "authorized"]:
|
||||||
|
return _cmd_show_or_clear(args)
|
||||||
|
if args[0] == "blocklist":
|
||||||
|
return _cmd_as_blocklist(args)
|
||||||
|
if args[0] == "whitelist":
|
||||||
|
return _cmd_as_whitelist(args)
|
||||||
|
if args[0] == "egg":
|
||||||
|
global _egg_counter
|
||||||
|
if _egg_counter == 10:
|
||||||
|
prof.cons_show(f"Do you know that it's an antispam plugin and not an egg farm? No more eggs for you!")
|
||||||
|
return
|
||||||
|
_egg_counter += 1
|
||||||
|
prof.cons_show(f"Egg number {_egg_counter} has been planted.")
|
||||||
|
if _egg_counter == 5:
|
||||||
|
prof.cons_show(f"What do you need so many eggs for?")
|
||||||
|
return
|
||||||
|
if args[0] == "roster":
|
||||||
|
prof.cons_show("\n".join(_roster))
|
||||||
|
return
|
||||||
|
prof.cons_bad_cmd_usage('/antispam')
|
||||||
|
|
||||||
|
def _cmd_show_or_clear(args):
|
||||||
|
if len(args) == 1:
|
||||||
|
return _show_page(args[0])
|
||||||
|
if len(args) == 2:
|
||||||
|
if args[1] == "clear":
|
||||||
|
if prof.settings_string_list_clear("antispam", args[0]):
|
||||||
|
prof.cons_show(f'{args[0].capitalize()} has been cleared.')
|
||||||
|
else:
|
||||||
|
prof.cons_show(f'{args[0].capitalize()} is already empty.')
|
||||||
|
return
|
||||||
|
return _show_page(args[0], args[1])
|
||||||
|
prof.cons_bad_cmd_usage('/antispam')
|
||||||
|
|
||||||
|
def _cmd_as_blocklist(args):
|
||||||
|
if len(args) < 3:
|
||||||
|
return _cmd_show_or_clear(args)
|
||||||
|
if args[1] == "add":
|
||||||
|
for jid in args[2:]:
|
||||||
|
ban_time = _ban_user(jid, full_jid=False, time_limited=False)
|
||||||
|
prof.cons_show(f'JID "{jid}" has been banned {ban_time}.')
|
||||||
|
elif args[1] == "remove":
|
||||||
|
for jid in args[2:]:
|
||||||
|
if _unban_user(jid):
|
||||||
|
prof.cons_show(f'JID "{jid}" has been unbanned.')
|
||||||
|
else:
|
||||||
|
prof.cons_show(f'JID "{jid}" has not been found in the blocklist.')
|
||||||
|
|
||||||
|
def _cmd_as_whitelist(args):
|
||||||
|
if len(args) < 3:
|
||||||
|
return _cmd_show_or_clear(args)
|
||||||
|
if args[1] == "add":
|
||||||
|
for jid in args[2:]:
|
||||||
|
prof.settings_string_list_add("antispam", "whitelist", jid)
|
||||||
|
prof.cons_show(f'JID "{jid}" has been whitelisted.')
|
||||||
|
elif args[1] == "remove":
|
||||||
|
for jid in args[2:]:
|
||||||
|
if prof.settings_string_list_remove("antispam", "whitelist", jid):
|
||||||
|
prof.cons_show(f'JID "{jid}" has been removed from the whitelist.')
|
||||||
|
else:
|
||||||
|
prof.cons_show(f'JID "{jid}" has not been found in the whitelist.')
|
||||||
|
|
||||||
|
def _show_cmd_error(error="", user_mistake=True) -> None:
|
||||||
|
"""Used to shows str:error when user typed wrong input"""
|
||||||
|
if user_mistake:
|
||||||
|
prof.cons_bad_cmd_usage('/antispam')
|
||||||
|
if error:
|
||||||
|
prof.cons_show(error)
|
||||||
|
|
||||||
|
|
||||||
|
def _set_default_values(key) -> bool:
|
||||||
|
default_value = _antispam_defaults[key]
|
||||||
|
if (key in _as_settings_strings):
|
||||||
|
prof.settings_string_set("antispam", key, default_value)
|
||||||
|
elif (key in _as_settings_ints):
|
||||||
|
prof.settings_int_set("antispam", key, default_value)
|
||||||
|
prof.cons_show(f'Antispam setting {key} was successfully set to its default ({default_value}).')
|
||||||
|
|
||||||
|
def _set_values(key, value) -> bool:
|
||||||
|
"""Returns Bool True if values has been set, False is value is invalid"""
|
||||||
|
value = ' '.join(value)
|
||||||
|
if key in _as_settings_strings:
|
||||||
|
prof.settings_string_set("antispam", key, value)
|
||||||
|
return True
|
||||||
|
if key in _as_settings_ints:
|
||||||
|
min_val, max_val = _as_settings_ints[key]['min'], _as_settings_ints[key]['max']
|
||||||
|
if not _represents_int_in_range(value, min_val, max_val):
|
||||||
|
prof.cons_show(f'Value of {key} must be an integer between {min_val} and {max_val}!')
|
||||||
|
return False
|
||||||
|
prof.settings_int_set("antispam", key, int(value))
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _parse_tag_content(stanza, tag):
|
||||||
|
tmp = re.search(f"<{tag}.*?>([\S\s]*?)</{tag}>", stanza) # don't blame me, it works :D
|
||||||
|
try:
|
||||||
|
return tmp.group(1) if tmp else ""
|
||||||
|
except IndexError as e:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def _parse_attr(stanza, attribute) -> str:
|
||||||
|
"""Parse attribute from the first tag"""
|
||||||
|
tmp = re.search(f'^\s*<[^>]+{attribute}="([^"]+)"', stanza)
|
||||||
|
try:
|
||||||
|
return tmp.group(1) if tmp else ""
|
||||||
|
except IndexError as e:
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def _parse_sender(stanza) -> str:
|
||||||
|
"""Returns sender from stanza or empty string if not found"""
|
||||||
|
if "<forwarded" in stanza:
|
||||||
|
stanza = _parse_tag_content(stanza, "forwarded")
|
||||||
|
return _parse_attr(stanza, "from").split('/', 1)[0]
|
||||||
|
|
||||||
|
def _parse_id(stanza) -> str:
|
||||||
|
"""Returns id from stanza or empty string if not found"""
|
||||||
|
return _parse_attr(stanza, "id")
|
||||||
|
|
||||||
|
def _is_dry_mode() -> bool:
|
||||||
|
return _get_string_setting("dry") == "on"
|
||||||
|
|
||||||
|
def _antispam_check_wrapper(stanza, stanza_type) -> bool:
|
||||||
|
result = _antispam_check(stanza, stanza_type)
|
||||||
|
dry_mode = _is_dry_mode()
|
||||||
|
if not result:
|
||||||
|
if _get_string_setting("debug") == "on" or dry_mode:
|
||||||
|
prof.cons_show(f"[AntiSpam{' (DryMode)' if dry_mode else ''}] Blocked stanza: {stanza}")
|
||||||
|
else:
|
||||||
|
prof.log_debug(f"[AntiSpam] Blocked stanza: {stanza}")
|
||||||
|
return result or _is_dry_mode()
|
||||||
|
|
||||||
|
def _antispam_check(stanza, stanza_type) -> bool:
|
||||||
|
"""Returns Bool True if message is not spam, False if message should be blocked (spam/unverified sender)"""
|
||||||
|
sender = _parse_sender(stanza)
|
||||||
|
stanza_id = _parse_id(stanza)
|
||||||
|
if not sender and "from=" in stanza:
|
||||||
|
prof.log_warning(f"In the following stanza From is present, but not catched: \n{stanza}")
|
||||||
|
if not _is_activated():
|
||||||
|
return True
|
||||||
|
if _is_whitelisted(sender) or _is_in_roster(sender):
|
||||||
|
return True
|
||||||
|
if _is_banned(sender):
|
||||||
|
return False
|
||||||
|
if _is_authorized(sender):
|
||||||
|
return True
|
||||||
|
if not _roster:
|
||||||
|
prof.log_debug(f"[AntiSpam] Passed message because roster was empty. Stanza: {stanza}")
|
||||||
|
return True
|
||||||
|
if stanza_type == "presence":
|
||||||
|
if re.search('^\s*<presence.+type="subscribe".+>', stanza):
|
||||||
|
_send_stanza(f'<presence type="unsubscribed" to="{sender}" />')
|
||||||
|
_send_stanza(f'<message type="chat" to="{sender}"><subject>{_get_string_setting("msg")}</subject><body>{_get_string_setting("question")}</body></message>')
|
||||||
|
_counter_inc(sender)
|
||||||
|
elif stanza_type == "iq":
|
||||||
|
if re.search('^\s*<iq[^>]+type="set"', stanza):
|
||||||
|
to = f'to="{sender}" ' if sender else ''
|
||||||
|
_send_stanza(f'<iq type="error" id="{stanza_id}" {to}/>')
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
elif stanza_type == "msg":
|
||||||
|
if _parse_attr(stanza, "type") == "error":
|
||||||
|
prof.settings_string_list_add("antispam", "history", f"{_get_time()}|{sender}|{_parse_tag_content(stanza, 'body')}")
|
||||||
|
return False
|
||||||
|
if not _is_correct_answer(stanza):
|
||||||
|
if (is_otr_requested := "OTRv2" in stanza):
|
||||||
|
_send_stanza(f'<message type="chat" to="{sender}"><body>{_get_string_setting("otrmsg")}</body></message>')
|
||||||
|
prof.settings_string_list_add("antispam", "history", f"{_get_time()}|{sender}|{_parse_tag_content(stanza, 'body')}")
|
||||||
|
wrong_tries = _get_counter(sender)
|
||||||
|
subject = f'<subject>{_get_string_setting("msg")}</subject>' if wrong_tries == 0 else ''
|
||||||
|
wrong_answer = _get_string_setting("errormsg")+'\n' if wrong_tries > 0 and not is_otr_requested else ''
|
||||||
|
_send_stanza(f'<message type="chat" to="{sender}">{subject}<body>{wrong_answer}{_get_string_setting("question")}</body></message>')
|
||||||
|
_counter_inc(sender)
|
||||||
|
return False
|
||||||
|
prof.settings_string_list_add("antispam", "authorized", sender)
|
||||||
|
_send_stanza(f'<message type="chat" to="{sender}"><body>{_get_string_setting("donemsg")}</body></message>')
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _force_update_roster(myjid=None) -> None:
|
||||||
|
global _roster
|
||||||
|
if not _roster and myjid:
|
||||||
|
_roster = [myjid]
|
||||||
|
prof.send_stanza(f'<iq id="{uuid4()}" type="get"><query xmlns="jabber:iq:roster"/>\</iq>')
|
||||||
|
return
|
||||||
|
|
||||||
|
def _update_roster(stanza) -> None:
|
||||||
|
global _roster
|
||||||
|
_roster = [
|
||||||
|
*re.findall('<iq[^>]+to="([^"/]+)["/]', stanza),
|
||||||
|
*[x for x,y in re.findall('<item[^>]+jid="([^"]+?)"[^>]+subscription="([^"]+?)"', stanza) if y == "both" or y == "to"],
|
||||||
|
*[x for y,x in re.findall('<item[^>]+subscription="([^"]+?)"[^>]+jid="([^"]+?)"', stanza) if y == "both" or y == "to"],
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _is_activated() -> bool:
|
||||||
|
return prof.settings_boolean_get("antispam", "enabled", True)
|
||||||
|
|
||||||
|
def _update_banned_list() -> None:
|
||||||
|
ban_list = prof.settings_string_list_get("antispam", "blocklist") or []
|
||||||
|
for banned_user in ban_list:
|
||||||
|
if not (tmp := _unpack_banned_user(banned_user)):
|
||||||
|
continue
|
||||||
|
ban_time, ban_type, jid = tmp
|
||||||
|
if ban_time != "Forever" and not _is_future_time(ban_time):
|
||||||
|
unbanmsg = _get_string_setting("unbanmsg")
|
||||||
|
if unbanmsg != "None":
|
||||||
|
_send_stanza(f'<message type="chat" to="{jid}"><body>{unbanmsg}</body></message>')
|
||||||
|
prof.settings_string_list_remove("antispam", "blocklist", banned_user)
|
||||||
|
return
|
||||||
|
|
||||||
|
def _unpack_banned_user(banned_user):
|
||||||
|
"""Returns None or Tuple of banned user info in (time_banned, ban_type, jid) format"""
|
||||||
|
tmp = banned_user.split("|", 2)
|
||||||
|
if len(tmp) != 3:
|
||||||
|
prof.cons_show(f"Problem on banned user unpacking: \"{banned_user}\". Deleting...")
|
||||||
|
prof.settings_string_list_remove("antispam", "blocklist", banned_user)
|
||||||
|
return
|
||||||
|
return tmp
|
||||||
|
|
||||||
|
def _is_in_roster(jid) -> bool:
|
||||||
|
return jid in _roster
|
||||||
|
|
||||||
|
def _is_authorized(jid) -> bool:
|
||||||
|
return jid in (prof.settings_string_list_get("antispam", "authorized") or [])
|
||||||
|
|
||||||
|
def _is_banned(jid) -> bool:
|
||||||
|
ban_list = prof.settings_string_list_get("antispam", "blocklist") or []
|
||||||
|
for banned_user in ban_list:
|
||||||
|
if not (tmp := _unpack_banned_user(banned_user)):
|
||||||
|
continue
|
||||||
|
ban_time, ban_type, bjid = tmp
|
||||||
|
if ban_type == "F": # On full JID ban (e.g. "user@example.com")
|
||||||
|
if jid == bjid and (ban_time == "Forever" or _is_future_time(ban_time)):
|
||||||
|
return True
|
||||||
|
else: # On partial JID ban (e.g. "@example.com", "spammer")
|
||||||
|
if bjid in jid and (ban_time == "Forever" or _is_future_time(ban_time)):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _is_whitelisted(jid) -> bool:
|
||||||
|
wl_users = (prof.settings_string_list_get("antispam", "whitelist") or [])
|
||||||
|
return any(wj in jid for wj in wl_users)
|
||||||
|
|
||||||
|
def _get_validate_count(c):
|
||||||
|
tmp = c.split('|', 1)
|
||||||
|
if len(tmp) != 2:
|
||||||
|
prof.log_warning(f'Invalid counter entry: "{c}". Removing...')
|
||||||
|
prof.settings_string_list_remove("antispam", "counter", c)
|
||||||
|
return
|
||||||
|
return int(tmp[0]), tmp[1]
|
||||||
|
|
||||||
|
def _counter_inc(jid) -> None:
|
||||||
|
counter = prof.settings_string_list_get("antispam", "counter") or []
|
||||||
|
for c in counter:
|
||||||
|
if not (tmp := _get_validate_count(c)):
|
||||||
|
continue
|
||||||
|
count, cjid = tmp
|
||||||
|
if jid == cjid:
|
||||||
|
prof.settings_string_list_remove("antispam", "counter", c)
|
||||||
|
prof.settings_string_list_add("antispam", "counter", f"{count+1}|{jid}")
|
||||||
|
if count % _get_int_setting("maxtries") == 0:
|
||||||
|
ban_time = _ban_user(jid)
|
||||||
|
blockmsg = _get_string_setting("blockmsg").replace('{}', str(ban_time))
|
||||||
|
_send_stanza(f'<message type="chat" to="{jid}"><body>{blockmsg}</body></message>')
|
||||||
|
return
|
||||||
|
prof.settings_string_list_add("antispam", "counter", f"1|{jid}")
|
||||||
|
|
||||||
|
|
||||||
|
def _get_counter(jid) -> int:
|
||||||
|
counter = prof.settings_string_list_get("antispam", "counter") or []
|
||||||
|
for c in counter:
|
||||||
|
if not (tmp := _get_validate_count(c)):
|
||||||
|
continue
|
||||||
|
count, cjid = tmp
|
||||||
|
if jid == cjid:
|
||||||
|
return count
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def _show_page(table, page_num=1) -> None:
|
||||||
|
"""Shows a page from table N (table is fetched from string_list setting with name) to plugin user through cons_show."""
|
||||||
|
if not _represents_int_in_range(page_num, 1):
|
||||||
|
prof.cons_show("Use correct page number. It must be integer from 1 to 10000.")
|
||||||
|
return
|
||||||
|
page_num = int(page_num)
|
||||||
|
page = page_num-1
|
||||||
|
table_content = prof.settings_string_list_get("antispam", table) or []
|
||||||
|
table_size = len(table_content)
|
||||||
|
total_pages = math.ceil(table_size/_page_limit)
|
||||||
|
if not table_content:
|
||||||
|
return prof.cons_show(f"Nothing to display, {table} is empty")
|
||||||
|
if page_num > total_pages:
|
||||||
|
return prof.cons_show(f"Page {page_num} does not exist. There are only {total_pages} pages")
|
||||||
|
page_content = table_content[page*_page_limit:page_num*_page_limit]
|
||||||
|
if not page_content:
|
||||||
|
return prof.cons_show(f"Nothing to display, {table} on Page {page_num} is empty")
|
||||||
|
for x in page_content:
|
||||||
|
formatting = (lambda x: x)
|
||||||
|
prof.cons_show(formatting(x))
|
||||||
|
prof.cons_show(f"Page {page_num}/{total_pages}. Currently {table_size} entries.")
|
||||||
|
|
||||||
|
def _ban_user(jid, full_jid=True, time_limited=True, custom_time_limit=None):
|
||||||
|
"""Adds user to ban list"""
|
||||||
|
ban_type = "F" if full_jid else "P"
|
||||||
|
if time_limited and (ban_time := custom_time_limit if custom_time_limit else _get_int_setting("blocktime")) != -1:
|
||||||
|
ban_time_formatted = (datetime.datetime.now() + datetime.timedelta(minutes=ban_time)).strftime("%d.%m.%Y %H:%M:%S")
|
||||||
|
_unban_user(jid)
|
||||||
|
prof.settings_string_list_add("antispam", "blocklist", f"{ban_time_formatted}|{ban_type}|{jid}")
|
||||||
|
return ban_time
|
||||||
|
prof.settings_string_list_add("antispam", "blocklist", f"Forever|{ban_type}|{jid}")
|
||||||
|
return "forever"
|
||||||
|
|
||||||
|
def _unban_user(jid):
|
||||||
|
"""Removes user from ban list. True on success, otherwise false."""
|
||||||
|
ban_list = prof.settings_string_list_get("antispam", "blocklist") or []
|
||||||
|
for banned_user in ban_list:
|
||||||
|
if not (tmp := _unpack_banned_user(banned_user)):
|
||||||
|
continue
|
||||||
|
ban_time, ban_type, bjid = tmp
|
||||||
|
if bjid == jid:
|
||||||
|
return prof.settings_string_list_remove("antispam", "blocklist", banned_user)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
# Settings utils
|
||||||
|
|
||||||
|
def _get_string_setting(setting) -> str:
|
||||||
|
return prof.settings_string_get("antispam", setting, _antispam_defaults[setting])
|
||||||
|
|
||||||
|
def _get_int_setting(setting) -> int:
|
||||||
|
return prof.settings_int_get("antispam", setting, _antispam_defaults[setting])
|
||||||
|
|
||||||
|
# Utils
|
||||||
|
|
||||||
|
def _prep_alias(replace_list):
|
||||||
|
return [x.replace("/antispam", "/as") for x in replace_list]
|
||||||
|
|
||||||
|
def _is_correct_answer(stanza):
|
||||||
|
correct_answer = _get_string_setting('answer')
|
||||||
|
answer = _parse_tag_content(stanza, "body")
|
||||||
|
if not answer:
|
||||||
|
prof.log_warning(f'Invalid mesage stanza. Ignoring user input. Stanza: {stanza}')
|
||||||
|
return False
|
||||||
|
return answer.strip().lower() == correct_answer.strip().lower()
|
||||||
|
|
||||||
|
def _is_future_time(time) -> bool:
|
||||||
|
"""Checks formatted time and returns True if time from parameter is in the future"""
|
||||||
|
try:
|
||||||
|
ptime = datetime.datetime.strptime(time, _time_format)
|
||||||
|
except ValueError as e:
|
||||||
|
prof.log_error(f"Exception raised when time was compared (input time: {time})\n{e}")
|
||||||
|
return True
|
||||||
|
return ptime > datetime.datetime.now()
|
||||||
|
|
||||||
|
def _get_time():
|
||||||
|
"""Returns current time formatted"""
|
||||||
|
return datetime.datetime.now().strftime(_time_format)
|
||||||
|
|
||||||
|
def _represents_int_in_range(s, num_min=-1, num_max=10000) -> bool:
|
||||||
|
"""Returns True if passed number is integer and it is in provided range (from -1 to 10000 by default)"""
|
||||||
|
try:
|
||||||
|
num = int(s)
|
||||||
|
return num >= num_min and num <= num_max
|
||||||
|
except ValueError:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
def _send_stanza(stanza):
|
||||||
|
if not _is_dry_mode():
|
||||||
|
return prof.send_stanza(stanza)
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
"""
|
"""
|
||||||
Print something in ASCII text.
|
Print something in ASCII text.
|
||||||
|
|
||||||
Running from the console will print the text to the console.
|
Running from the console will print the text to the console.
|
||||||
Running in a chat or room window will send the ASCII text
|
Running in a chat or room window will send the ASCII text
|
||||||
|
|
||||||
110
src/autocorrector.py
Normal file
110
src/autocorrector.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
"""
|
||||||
|
autocorrector - Replace common typos
|
||||||
|
|
||||||
|
My typing style is such a mess. But I invest more time in correcting it
|
||||||
|
programmatically than training myself to type better. Maybe thats the
|
||||||
|
problem? Anyway, here is a plugin for all keyboard messies like me.
|
||||||
|
"""
|
||||||
|
import prof
|
||||||
|
|
||||||
|
def prof_pre_chat_message_send(barejid, message):
|
||||||
|
enabled = prof.settings_string_get("autocorrector", "enabled", "on")
|
||||||
|
if enabled == "off":
|
||||||
|
return message
|
||||||
|
else:
|
||||||
|
replacements = prof.settings_string_list_get("autocorrector","replacements")
|
||||||
|
for replacement in replacements:
|
||||||
|
repl=replacement.split(':')
|
||||||
|
message=message.replace(repl[0],repl[1])
|
||||||
|
return message
|
||||||
|
|
||||||
|
def prof_pre_priv_message_send(barejid, nick, message):
|
||||||
|
enabled = prof.settings_string_get("autocorrector", "enabled", "on")
|
||||||
|
if enabled == "off":
|
||||||
|
return message
|
||||||
|
else:
|
||||||
|
replacements = prof.settings_string_list_get("autocorrector","replacements")
|
||||||
|
for replacement in replacements:
|
||||||
|
repl=replacement.split(':')
|
||||||
|
message=message.replace(repl[0],repl[1])
|
||||||
|
return message
|
||||||
|
|
||||||
|
def prof_pre_room_message_send(barejid, message):
|
||||||
|
enabled = prof.settings_string_get("autocorrector", "enabled", "on")
|
||||||
|
if enabled == "off":
|
||||||
|
return message
|
||||||
|
else:
|
||||||
|
replacements = prof.settings_string_list_get("autocorrector","replacements")
|
||||||
|
for replacement in replacements:
|
||||||
|
repl=replacement.split(':')
|
||||||
|
message=message.replace(repl[0],repl[1])
|
||||||
|
return message
|
||||||
|
|
||||||
|
def _cmd_autocorrector(arg1=None, arg2=None):
|
||||||
|
if arg1 == "on":
|
||||||
|
prof.settings_string_set("autocorrector", "enabled", "on")
|
||||||
|
prof.cons_show("autocorrector plugin enabled")
|
||||||
|
elif arg1 == "off":
|
||||||
|
prof.settings_string_set("autocorrector", "enabled", "off")
|
||||||
|
prof.cons_show("autocorrector plugin disabled")
|
||||||
|
elif arg1 == "clearall":
|
||||||
|
prof.settings_string_list_clear("autocorrector","replacements")
|
||||||
|
prof.cons_show("autocorrector plugin replacement list cleared.")
|
||||||
|
elif arg1 == "showlist":
|
||||||
|
replacements = prof.settings_string_list_get("autocorrector","replacements")
|
||||||
|
prof.cons_show("Replacement string list:")
|
||||||
|
for replacement in replacements:
|
||||||
|
prof.cons_show(replacement)
|
||||||
|
elif arg1 == "add":
|
||||||
|
if arg2 == None:
|
||||||
|
prof.cons_bad_cmd_usage("/autocorrector")
|
||||||
|
else:
|
||||||
|
if len(arg2.split(':')) == 2:
|
||||||
|
prof.settings_string_list_add("autocorrector","replacements",arg2)
|
||||||
|
prof.cons_show("Replacement String added.")
|
||||||
|
else:
|
||||||
|
prof.cons_show("Invalid replacement String. Please use the following format to specify replacements: pattern:replacement.")
|
||||||
|
elif arg1 == "rm":
|
||||||
|
if arg2 == None:
|
||||||
|
prof.cons_bad_cmd_usage("/autocorrector")
|
||||||
|
else:
|
||||||
|
if len(arg2.split(':')) == 2:
|
||||||
|
prof.settings_string_list_remove("autocorrector","replacements",arg2)
|
||||||
|
prof.cons_show("Replacement String removed.")
|
||||||
|
else:
|
||||||
|
prof.cons_show("Invalid replacement String. Please use the following format to specify replacements: pattern:replacement.")
|
||||||
|
else:
|
||||||
|
enabled = prof.settings_string_get("autocorrector", "enabled", "on")
|
||||||
|
if enabled == "off":
|
||||||
|
prof.cons_show("autocorrector inactive.")
|
||||||
|
else:
|
||||||
|
prof.cons_show("autocorrector active.")
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
synopsis = [
|
||||||
|
"/autocorrector on|off",
|
||||||
|
"/autocorrector showlist",
|
||||||
|
"/autocorrector clearall",
|
||||||
|
"/autocorrector add"
|
||||||
|
"/autocorrector rm"
|
||||||
|
]
|
||||||
|
description = "Messy typist autocorrector. Replaces common typos in your outgoing messages."
|
||||||
|
args = [
|
||||||
|
[ "on|off", "Enable/disable correction for all windows" ],
|
||||||
|
[ "showlist", "show typolist." ],
|
||||||
|
[ "add", "Add entry to typolist. Use pattern:replacement as format." ],
|
||||||
|
[ "rm", "Remove entry from typolist. Use pattern:replacement as format." ],
|
||||||
|
[ "clearall", "Remove all entries from typolist" ]
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/autocorrector on",
|
||||||
|
"/autocorrector add tpyo:typo",
|
||||||
|
"/autocorrector add tset:test",
|
||||||
|
"/autocorrector rm tset:test",
|
||||||
|
"/autocorrector showlist",
|
||||||
|
]
|
||||||
|
|
||||||
|
prof.settings_string_set("autocorrector", "enabled", "on")
|
||||||
|
prof.register_command("/autocorrector", 0, 2, synopsis, description, args, examples, _cmd_autocorrector)
|
||||||
|
prof.completer_add("/autocorrector", [ "on", "off", "clearall", "add", "rm", "showlist" ])
|
||||||
|
|
||||||
121
src/browser.py
Normal file
121
src/browser.py
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
"""
|
||||||
|
Open the last link received in a chat or room window using the systems default browser
|
||||||
|
"""
|
||||||
|
|
||||||
|
import prof
|
||||||
|
import os
|
||||||
|
import webbrowser
|
||||||
|
import re
|
||||||
|
|
||||||
|
_links = {}
|
||||||
|
_lastlink = {}
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_browser(url):
|
||||||
|
global _lastlink
|
||||||
|
link = None
|
||||||
|
|
||||||
|
# use arg if supplied
|
||||||
|
if (url is not None):
|
||||||
|
link = url
|
||||||
|
else:
|
||||||
|
jid = prof.get_current_recipient()
|
||||||
|
room = prof.get_current_muc()
|
||||||
|
|
||||||
|
# check if in chat window
|
||||||
|
if (jid is not None):
|
||||||
|
|
||||||
|
# check for link from recipient
|
||||||
|
if jid in _lastlink.keys():
|
||||||
|
link = _lastlink[jid]
|
||||||
|
else:
|
||||||
|
prof.cons_show("No links found from " + jid)
|
||||||
|
|
||||||
|
# check if in muc window
|
||||||
|
elif (room is not None):
|
||||||
|
if room in _lastlink.keys():
|
||||||
|
link = _lastlink[room]
|
||||||
|
else:
|
||||||
|
prof.cons_show("No links found from " + room)
|
||||||
|
|
||||||
|
# not in chat/muc window
|
||||||
|
else:
|
||||||
|
prof.cons_show("You must supply a URL to the /browser command")
|
||||||
|
|
||||||
|
# open the browser if link found
|
||||||
|
if (link is not None):
|
||||||
|
prof.cons_show("Opening " + link + " in browser")
|
||||||
|
_open_browser(link)
|
||||||
|
|
||||||
|
|
||||||
|
def _open_browser(url):
|
||||||
|
savout = os.dup(1)
|
||||||
|
saverr = os.dup(2)
|
||||||
|
os.close(1)
|
||||||
|
os.close(2)
|
||||||
|
os.open(os.devnull, os.O_RDWR)
|
||||||
|
try:
|
||||||
|
webbrowser.open(url, new=2)
|
||||||
|
finally:
|
||||||
|
os.dup2(savout, 1)
|
||||||
|
os.dup2(saverr, 2)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
synopsis = [
|
||||||
|
"/browser",
|
||||||
|
"/browser <url>"
|
||||||
|
]
|
||||||
|
description = "View a URL in the systems default browser. If no argument is supplied, the last URL in the current chat or room will be used. " \
|
||||||
|
"Tab autocompletion will go through all previous links in the current chat/room"
|
||||||
|
args = [
|
||||||
|
[ "<url>", "URL to open in the browser" ]
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/browser http://jabber.space/"
|
||||||
|
]
|
||||||
|
|
||||||
|
prof.register_command("/browser", 0, 1, synopsis, description, args, examples, _cmd_browser)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_chat_win_focus(barejid):
|
||||||
|
prof.completer_clear("/browser")
|
||||||
|
if barejid in _links:
|
||||||
|
prof.completer_add("/browser", _links[barejid])
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_room_win_focus(barejid):
|
||||||
|
prof.completer_clear("/browser")
|
||||||
|
if barejid in _links:
|
||||||
|
prof.completer_add("/browser", _links[barejid])
|
||||||
|
|
||||||
|
|
||||||
|
def _process_message(barejid, current_jid, message):
|
||||||
|
links = re.findall(r'(https?://\S+)', message)
|
||||||
|
if (len(links) > 0):
|
||||||
|
if barejid not in _links:
|
||||||
|
_links[barejid] = []
|
||||||
|
# add to list of links for barejid
|
||||||
|
for link in links:
|
||||||
|
if link not in _links[barejid]:
|
||||||
|
_links[barejid].append(link)
|
||||||
|
# add to autocompleter if message for current window
|
||||||
|
if current_jid == barejid:
|
||||||
|
prof.completer_add("/browser", _links[barejid])
|
||||||
|
# set last link for barejid
|
||||||
|
_lastlink[barejid] = links[len(links)-1]
|
||||||
|
|
||||||
|
|
||||||
|
def prof_post_chat_message_display(barejid, resource, message):
|
||||||
|
current_jid = prof.get_current_recipient()
|
||||||
|
_process_message(barejid, current_jid, message)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_post_room_message_display(barejid, nick, message):
|
||||||
|
current_jid = prof.get_current_muc()
|
||||||
|
_process_message(barejid, current_jid, message)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_room_history_message(barejid, nick, message, timestamp):
|
||||||
|
current_jid = prof.get_current_muc()
|
||||||
|
_process_message(barejid, current_jid, message)
|
||||||
7
src/c/moj/.gitignore
vendored
Normal file
7
src/c/moj/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
moj
|
||||||
|
moj.exe
|
||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
gen/lookup.c
|
||||||
|
gen/emoji.json
|
||||||
|
gen/emoji.csv
|
||||||
15
src/c/moj/COPYING
Normal file
15
src/c/moj/COPYING
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
ISC License
|
||||||
|
|
||||||
|
Copyright (c) 2018, Adrian "vifino" Pistol
|
||||||
|
|
||||||
|
Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
purpose with or without fee is hereby granted, provided that the above
|
||||||
|
copyright notice and this permission notice appear in all copies.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
68
src/c/moj/Makefile
Normal file
68
src/c/moj/Makefile
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
# moj makefile
|
||||||
|
CC ?= cc
|
||||||
|
|
||||||
|
MOJILIST=https://raw.githubusercontent.com/milesj/emojibase/master/packages/data/en/raw.json
|
||||||
|
|
||||||
|
# Do not touch.
|
||||||
|
all: moj libmoj.so
|
||||||
|
|
||||||
|
# Generate lookup lists
|
||||||
|
gen/emoji.json:
|
||||||
|
mkdir -p gen
|
||||||
|
wget -O $@ ${MOJILIST}
|
||||||
|
|
||||||
|
gen/emoji.csv: gen/emoji.json
|
||||||
|
jq -r '.[] | select(.emoji) | [.emoji] + .shortcodes | @csv' -- \
|
||||||
|
gen/emoji.json | \
|
||||||
|
sed 's/^"//;s/"$$//' | awk -f src/process.awk > $@
|
||||||
|
|
||||||
|
gen/emoji.gperf: src/gen_gperf.sh gen/emoji.csv
|
||||||
|
./src/gen_gperf.sh > ./gen/emoji.gperf
|
||||||
|
|
||||||
|
gen/emoji_list.h: src/gen_list.sh gen/emoji.csv
|
||||||
|
./src/gen_list.sh > $@
|
||||||
|
|
||||||
|
gen/lookup.c: gen/emoji.gperf
|
||||||
|
gperf --global-table --readonly-tables \
|
||||||
|
--struct-type --includes \
|
||||||
|
--compare-lengths --compare-strncmp \
|
||||||
|
--ignore-case -Q emoji_spool \
|
||||||
|
-H emoji_name_hash -N emoji_lookup_ref -m 3 \
|
||||||
|
--output-file=$@ $^
|
||||||
|
|
||||||
|
# Compile our code.
|
||||||
|
src/moj.o: gen/lookup.c gen/emoji_list.h src/moj.c
|
||||||
|
$(CC) -c ${CFLAGS} ${CPPFLAGS} -o $@ src/moj.c
|
||||||
|
|
||||||
|
libmoj.so: src/moj.o
|
||||||
|
$(CC) -shared -fPIC ${CFLAGS} ${CPPFLAGS} -o $@ ${LDFLAGS} $<
|
||||||
|
|
||||||
|
moj: src/main.c src/moj.o
|
||||||
|
$(CC) ${CFLAGS} ${CPPFLAGS} -o $@ ${LDFLAGS} $^
|
||||||
|
|
||||||
|
# Profanity plugin.
|
||||||
|
profanity_emoji.so: src/profanity_emoji.c src/moj.o
|
||||||
|
$(CC) -shared -fPIC ${CFLAGS} ${CPPFLAGS} -o $@ ${LDFLAGS} $^
|
||||||
|
|
||||||
|
profanity: profanity_emoji.so
|
||||||
|
|
||||||
|
# Install
|
||||||
|
install: moj
|
||||||
|
install -d $(DESTDIR)/$(PREFIX)/bin
|
||||||
|
install moj $(DESTDIR)/$(PREFIX)/bin
|
||||||
|
|
||||||
|
install-devel: libmoj.so
|
||||||
|
install -d $(DESTDIR)/$(PREFIX)/lib
|
||||||
|
install libmoj.so $(DESTDIR)/$(PREFIX)/lib
|
||||||
|
install -d $(DESTDIR)/$(PREFIX)/include
|
||||||
|
cp src/moj.h $(DESTDIR)/$(PREFIX)/include/libmoj.h
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f $(DESTDIR)/$(PREFIX)/bin/moj
|
||||||
|
uninstall-devel:
|
||||||
|
rm -f $(DESTDIR)/$(PREFIX)/lib/libmoj.so $(DESTDIR)/$(PREFIX)/include/libmoj.h
|
||||||
|
|
||||||
|
|
||||||
|
# Cleanup
|
||||||
|
clean:
|
||||||
|
rm -f moj gen/lookup.c src/*.o profanity_emoji.so
|
||||||
28
src/c/moj/README.md
Normal file
28
src/c/moj/README.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# moj
|
||||||
|
'moj is for those of us that want something more minimal than emojify.
|
||||||
|
|
||||||
|
Reasons to use moj instead of emojify:
|
||||||
|
- only 3 letters(!), huge reduction compared to 7 of emojify.
|
||||||
|
- written in C, compile time hash table generation, no interpreted language.
|
||||||
|
- VERY FAST. How does 0.002s to generate the average commit messages of this project sound? This is on a ThinkPad T61. A potato.
|
||||||
|
- data not mixed with code, only generated data/glue and handwritten code. (seperate files)
|
||||||
|
|
||||||
|
# Requirements
|
||||||
|
- Make (compile time)
|
||||||
|
- C99 compiler(?). (compile time)
|
||||||
|
- gperf (compile time)
|
||||||
|
|
||||||
|
No runtime deps.
|
||||||
|
|
||||||
|
To regen the emoji list you also need:
|
||||||
|
- wget
|
||||||
|
- jq
|
||||||
|
- awk
|
||||||
|
|
||||||
|
# Credits
|
||||||
|
[milesj/emojibase](https://github.com/milesj/emojibase) for the JSON Emoji list. Many thanks
|
||||||
|
|
||||||
|
vifino for doing everything else.
|
||||||
|
|
||||||
|
# License
|
||||||
|
ISC.
|
||||||
1810
src/c/moj/gen/emoji.gperf
Normal file
1810
src/c/moj/gen/emoji.gperf
Normal file
File diff suppressed because it is too large
Load Diff
1646
src/c/moj/gen/emoji_list.h
Normal file
1646
src/c/moj/gen/emoji_list.h
Normal file
File diff suppressed because it is too large
Load Diff
15
src/c/moj/src/gen_gperf.sh
Executable file
15
src/c/moj/src/gen_gperf.sh
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Generator for the hash list.
|
||||||
|
# This is unquestionably magic.
|
||||||
|
set -e
|
||||||
|
cat <<HEADER
|
||||||
|
%{
|
||||||
|
// THIS FILE IS GENERATED BY src/gen_list.sh.
|
||||||
|
// DO NOT TOUCH HERE.
|
||||||
|
%}
|
||||||
|
struct emoji_ref { char* name; unsigned int ref; };
|
||||||
|
%%
|
||||||
|
HEADER
|
||||||
|
|
||||||
|
cat gen/emoji.csv | sed 's/"//g' | \
|
||||||
|
awk -F',' '{ count++; for (i = 2; i <= NF; i++) printf "%s, %i\n", $i, count;}'
|
||||||
26
src/c/moj/src/gen_list.sh
Executable file
26
src/c/moj/src/gen_list.sh
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Generator for the actual emoji list.
|
||||||
|
set -e
|
||||||
|
|
||||||
|
EMOJIS=$(wc -l < gen/emoji.csv)
|
||||||
|
|
||||||
|
cat <<HEADER
|
||||||
|
// THIS FILE IS GENERATED BY src/gen_list.sh.
|
||||||
|
// DO NOT TOUCH HERE.
|
||||||
|
|
||||||
|
#define NUM_EMOJI $EMOJIS
|
||||||
|
static const char* emoji_list[$EMOJIS] = {
|
||||||
|
HEADER
|
||||||
|
|
||||||
|
gen() {
|
||||||
|
printf "\t\"%s\",\n" $1
|
||||||
|
}
|
||||||
|
|
||||||
|
cat gen/emoji.csv | sed 's/,/ /g' | while read -r input; do
|
||||||
|
gen $(eval "echo $input")
|
||||||
|
done
|
||||||
|
|
||||||
|
cat <<FOOTER
|
||||||
|
};
|
||||||
|
FOOTER
|
||||||
|
|
||||||
124
src/c/moj/src/main.c
Normal file
124
src/c/moj/src/main.c
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
// moj.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include "moj.h"
|
||||||
|
|
||||||
|
#define MODE_NORMAL 0
|
||||||
|
#define MODE_LOOKUP 1
|
||||||
|
#define MODE_USELIBRARY 2
|
||||||
|
|
||||||
|
void usage(char* name, int fail) {
|
||||||
|
FILE* f = stdout;
|
||||||
|
if (fail) f = stderr;
|
||||||
|
fprintf(f, "Usage: %s [-s sep] [-e] <:emoji: text>\n"
|
||||||
|
" -e: lookup mode - interpret arguments as emoji names\n"
|
||||||
|
" -s <sep>: use custom seperator\n", name);
|
||||||
|
exit(fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
if (argc < 2) {
|
||||||
|
usage(argv[0], 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse opts
|
||||||
|
int opt;
|
||||||
|
int mode = MODE_NORMAL;
|
||||||
|
char* sep = NULL;
|
||||||
|
while ((opt = getopt(argc, argv, "hels:")) != -1) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'h':
|
||||||
|
usage(argv[0], 0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case '?':
|
||||||
|
usage(argv[0], 1);
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
mode = MODE_LOOKUP;
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
sep = optarg;
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
mode = MODE_USELIBRARY;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind >= argc)
|
||||||
|
usage(argv[0], 1);
|
||||||
|
|
||||||
|
int argi;
|
||||||
|
switch (mode) {
|
||||||
|
case MODE_LOOKUP:
|
||||||
|
for (argi = optind; argi < argc; argi++) {
|
||||||
|
char* found = moj_lookup(argv[argi], strlen(argv[argi]));
|
||||||
|
if (found) {
|
||||||
|
printf("%s%s", found, sep ? sep : "\n");
|
||||||
|
} else {
|
||||||
|
printf("Couldn't find %s. :(\n", argv[argi]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sep) printf("\n");
|
||||||
|
break;
|
||||||
|
case MODE_NORMAL:
|
||||||
|
for (argi = optind; argi < argc; argi++) {
|
||||||
|
char* s = argv[argi];
|
||||||
|
char c;
|
||||||
|
int ci;
|
||||||
|
int len = strlen(s);
|
||||||
|
int start = 0;
|
||||||
|
int attention = 0;
|
||||||
|
for (ci = 0; ci <= len; ci++) {
|
||||||
|
c = s[ci];
|
||||||
|
|
||||||
|
if (attention) { // in :
|
||||||
|
if (c == ' ') {
|
||||||
|
attention = 0;
|
||||||
|
s[ci] = 0;
|
||||||
|
fprintf(stdout, "%s ", s + start);
|
||||||
|
} else if (c == ':') {
|
||||||
|
// check if start to ci - start -1 is a valid emoji.
|
||||||
|
s[ci] = 0;
|
||||||
|
char* found = moj_lookup(s + start + 1, ci - start - 1);
|
||||||
|
if (found) {
|
||||||
|
fprintf(stdout, "%s", found);
|
||||||
|
} else {
|
||||||
|
// not an emoji? oops.
|
||||||
|
fprintf(stdout, "%s:", s + start);
|
||||||
|
start = ci;
|
||||||
|
// the next might be one, though..
|
||||||
|
}
|
||||||
|
attention = 0;
|
||||||
|
}
|
||||||
|
} else if (c == ':' && ci < len) {
|
||||||
|
attention = 1;
|
||||||
|
start = ci;
|
||||||
|
} else {
|
||||||
|
putc(c, stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attention && start < len)
|
||||||
|
fprintf(stdout, "%s", s + start + 1);
|
||||||
|
|
||||||
|
if (argi < (argc - 1))
|
||||||
|
fputs(sep ? sep : " ", stdout);
|
||||||
|
}
|
||||||
|
fprintf(stdout, "\n");
|
||||||
|
break;
|
||||||
|
case MODE_USELIBRARY:
|
||||||
|
for (argi = optind; argi < argc; argi++) {
|
||||||
|
char* rep = moj_replace(argv[argi], strlen(argv[argi]));
|
||||||
|
printf("%s\n", rep);
|
||||||
|
free(rep);
|
||||||
|
}
|
||||||
|
break;;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
98
src/c/moj/src/moj.c
Normal file
98
src/c/moj/src/moj.c
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
// moj: Small Emoji library
|
||||||
|
// Based on our generated things.
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "../gen/lookup.c"
|
||||||
|
#include "../gen/emoji_list.h"
|
||||||
|
|
||||||
|
const char* moj_lookup(const char* name, size_t len) {
|
||||||
|
const struct emoji_ref *found = emoji_lookup_ref(name, len);
|
||||||
|
if (found) {
|
||||||
|
return emoji_list[found->ref - 1];
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* moj_replace(const char* text, size_t len) {
|
||||||
|
if (!len)
|
||||||
|
return strdup(text);
|
||||||
|
|
||||||
|
char c;
|
||||||
|
// count size delta to alloc a string just the right size.
|
||||||
|
int size_delta = 0;
|
||||||
|
|
||||||
|
size_t ci;
|
||||||
|
size_t start = 0;
|
||||||
|
size_t strend;
|
||||||
|
int attention = 0;
|
||||||
|
for (ci = 0; ci <= len; ci++) {
|
||||||
|
c = text[ci];
|
||||||
|
|
||||||
|
if (attention) { // in :
|
||||||
|
if (c == ' ') {
|
||||||
|
attention = 0;
|
||||||
|
} else if (c == ':') {
|
||||||
|
// check if start to ci - start -1 is a valid emoji.
|
||||||
|
size_t elen = ci - start - 1;
|
||||||
|
const char* found = moj_lookup(text + start + 1, elen);
|
||||||
|
if (found) {
|
||||||
|
size_delta += elen - strlen(found);
|
||||||
|
} else {
|
||||||
|
start = ci;
|
||||||
|
}
|
||||||
|
attention = 0;
|
||||||
|
}
|
||||||
|
} else if (c == ':' && ci < len) {
|
||||||
|
attention = 1;
|
||||||
|
start = ci;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// allocate buffer the right size.
|
||||||
|
size_t realsz = len + size_delta;
|
||||||
|
char* buf = malloc(realsz + 1);
|
||||||
|
if (!buf)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
start = 0;
|
||||||
|
attention = 0;
|
||||||
|
size_t offset = 0;
|
||||||
|
for (ci = 0; ci < len; ci++) {
|
||||||
|
c = text[ci];
|
||||||
|
|
||||||
|
if (attention) { // in :
|
||||||
|
if (c == ' ') {
|
||||||
|
attention = 0;
|
||||||
|
memcpy(buf + offset, text + start, ci - start + 1);
|
||||||
|
offset += ci - start + 1;
|
||||||
|
} else if (c == ':') {
|
||||||
|
// check if start to ci - start -1 is a valid emoji.
|
||||||
|
const char* found = moj_lookup(text + start + 1, ci - start - 1);
|
||||||
|
if (found) {
|
||||||
|
offset += sprintf(buf + offset, "%s", found);
|
||||||
|
} else {
|
||||||
|
// not an emoji? oops.
|
||||||
|
memcpy(buf + offset, text + start, ci - start + 1);
|
||||||
|
offset += ci - start + 1;
|
||||||
|
start = ci;
|
||||||
|
// the next might be one, though..
|
||||||
|
}
|
||||||
|
attention = 0;
|
||||||
|
}
|
||||||
|
} else if (c == ':' && ci < len) {
|
||||||
|
attention = 1;
|
||||||
|
start = ci;
|
||||||
|
} else {
|
||||||
|
buf[offset] = c;
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (attention) {
|
||||||
|
memcpy(buf + offset, text + start, ci - start);
|
||||||
|
offset += ci - start;
|
||||||
|
}
|
||||||
|
buf[realsz] = 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
5
src/c/moj/src/moj.h
Normal file
5
src/c/moj/src/moj.h
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
// moj: a small emoji library and cli.
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
char* moj_lookup(const char* name, size_t len);
|
||||||
|
char* moj_replace(const char* name, size_t len);
|
||||||
93
src/c/moj/src/process.awk
Normal file
93
src/c/moj/src/process.awk
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/awk -f
|
||||||
|
# This file takes in our CSV, emits simpler stuff.
|
||||||
|
# It also fixes up some things.
|
||||||
|
|
||||||
|
# Bunch of convenience functions.
|
||||||
|
function didsee(name) {
|
||||||
|
if (name in seen)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasnew() {
|
||||||
|
for (i = 2; i <= NF; i++)
|
||||||
|
if (!didsee($i))
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function newname(name) {
|
||||||
|
if (didsee(name))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
seen[name] = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function char(str, idx) {
|
||||||
|
return substr(str, idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function prefixed(name, prefixes) {
|
||||||
|
for (prefix in prefixes)
|
||||||
|
if (index(name, prefixes[prefix]) == 1)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function inarray(name, array) {
|
||||||
|
for (i in array)
|
||||||
|
if (array[i] == name)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function noing(name) {
|
||||||
|
# yep thats the name.
|
||||||
|
len = length(name);
|
||||||
|
if (len > 5 && substr(name, len - 2, 3) == "ing" && !prefixed(name, persons) && !inarray(name, exemptions)) {
|
||||||
|
if (char(name, len - 4) == char(name, len - 3)) {
|
||||||
|
# double letter combo, gg, nn, etc..
|
||||||
|
short = substr(name, 0, len - 4);
|
||||||
|
} else {
|
||||||
|
short = substr(name, 0, len - 3);
|
||||||
|
}
|
||||||
|
if (newname(short))
|
||||||
|
printf ",%s", short;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
FS="\",\""
|
||||||
|
|
||||||
|
# I hate this.
|
||||||
|
persons[1] = "person_";
|
||||||
|
persons[2] = "women_";
|
||||||
|
persons[3] = "woman_"
|
||||||
|
persons[4] = "men_";
|
||||||
|
persons[5] = "man_";
|
||||||
|
|
||||||
|
# I hate this even more.
|
||||||
|
exemptions[1] = "bowing";
|
||||||
|
exemptions[2] = "golfing";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if (hasnew())
|
||||||
|
printf "%s", $1;
|
||||||
|
|
||||||
|
for (i = 2; i <= NF; i++) {
|
||||||
|
if (newname($i)) {
|
||||||
|
printf ",%s", $i;
|
||||||
|
noing($i);
|
||||||
|
if (index($i, "person_") == 1) {
|
||||||
|
replaced = substr($i, 8);
|
||||||
|
if (newname(replaced)) {
|
||||||
|
printf ",%s", replaced;
|
||||||
|
}
|
||||||
|
noing(replaced);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf "\n";
|
||||||
|
}
|
||||||
10
src/c/moj/src/profanity_emoji.c
Normal file
10
src/c/moj/src/profanity_emoji.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
// moj: CProof plugin
|
||||||
|
// Intercepts text and replaces :emoji:
|
||||||
|
|
||||||
|
#include <profapi.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "moj.h"
|
||||||
|
|
||||||
|
char* prof_pre_chat_message_send(const char* const barejid, const char* message) {
|
||||||
|
return moj_replace(message, strlen(message)); // yep that is it.
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
Simple plugin to display the PID of the Profanity process and its parent
|
Simple plugin to display the PID of the CProof process and its parent
|
||||||
|
|
||||||
Theme example in ~/.local/share/profanity/plugin_themes
|
Theme example in ~/.local/share/profanity/plugin_themes
|
||||||
|
|
||||||
@@ -30,10 +30,10 @@ cmd_pid(char **args)
|
|||||||
void
|
void
|
||||||
prof_init(const char * const version, const char * const status, const char *const account_name, const char *const fulljid)
|
prof_init(const char * const version, const char * const status, const char *const account_name, const char *const fulljid)
|
||||||
{
|
{
|
||||||
const char *synopsis[] = { "/pid", NULL };
|
char *synopsis[] = { "/pid", NULL };
|
||||||
const char *description = "Show process ID and parent Process ID in the console window.";
|
char *description = "Show process ID and parent Process ID in the console window.";
|
||||||
const char *args[][2] = { { NULL, NULL } };
|
char *args[][2] = { { NULL, NULL } };
|
||||||
const char *examples[] = { NULL };
|
char *examples[] = { NULL };
|
||||||
|
|
||||||
prof_register_command("/pid", 0, 0, synopsis, description, args, examples, cmd_pid);
|
prof_register_command("/pid", 0, 0, synopsis, description, args, examples, cmd_pid);
|
||||||
}
|
}
|
||||||
@@ -63,6 +63,7 @@ def _sv_send(muc, occupant):
|
|||||||
ET.SubElement(iq, "query", {
|
ET.SubElement(iq, "query", {
|
||||||
"xmlns": "jabber:iq:version"
|
"xmlns": "jabber:iq:version"
|
||||||
})
|
})
|
||||||
|
|
||||||
iq_id_count = iq_id_count + 1
|
iq_id_count = iq_id_count + 1
|
||||||
|
|
||||||
prof.send_stanza(ET.tostring(iq))
|
prof.send_stanza(ET.tostring(iq))
|
||||||
@@ -71,10 +72,12 @@ def _sv_send(muc, occupant):
|
|||||||
def _cmd_clients():
|
def _cmd_clients():
|
||||||
muc = prof.get_current_muc()
|
muc = prof.get_current_muc()
|
||||||
if muc == None:
|
if muc == None:
|
||||||
|
prof.cons_show("Command only valid in chat rooms.")
|
||||||
return
|
return
|
||||||
|
|
||||||
occupants = prof.get_current_occupants()
|
occupants = prof.get_current_occupants()
|
||||||
if occupants == None or len(occupants) == 0:
|
if occupants == None or len(occupants) == 0:
|
||||||
|
prof.cons_show("No occupants for /clients command.")
|
||||||
return
|
return
|
||||||
|
|
||||||
nick = prof.get_current_nick()
|
nick = prof.get_current_nick()
|
||||||
33
src/emoticons.py
Normal file
33
src/emoticons.py
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
"""
|
||||||
|
Converts smileys in a text to their Unicode character representations.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import prof
|
||||||
|
|
||||||
|
EMOTICON_UNICODE_DICT = {':)': '😃', ':(': '☹️', ':D': '😃', ':O': '😲', ';)': '😉', ':-)': '😊', ':-D': '😁', ':-(': '😞',
|
||||||
|
';-)': '😜', '<3': '❤️', ':P': '😛', ':|': '😐', ':/': '😕', ':*': '😘', ':]': '😃', ':[': '😢',
|
||||||
|
':-|': '😐', ':\\': '😕', ':3': '😺', 'O:)': '😇', '>:(': '😠', ':poop:': '💩', ':fire:': '🔥',
|
||||||
|
':heart:': '❤️', ':thumbsup:': '👍', ':star:': '⭐', ':beer:': '🍺', ':pizza:': '🍕', ':sunglasses:': '😎',
|
||||||
|
':ok_hand:': '👌', ':heart_eyes:': '😍'}
|
||||||
|
|
||||||
|
|
||||||
|
def replace_emoticons(text, emoticon_dict):
|
||||||
|
for emoticon, unicode_char in emoticon_dict.items():
|
||||||
|
text = text.replace(emoticon, unicode_char)
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
|
def convert_emoticons(input_str):
|
||||||
|
return replace_emoticons(input_str, EMOTICON_UNICODE_DICT)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_pre_chat_message_display(barejid, resource, message):
|
||||||
|
return convert_emoticons(message)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_pre_room_message_display(barejid, nick, message):
|
||||||
|
return convert_emoticons(message)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_pre_priv_message_display(barejid, nick, message):
|
||||||
|
return convert_emoticons(message)
|
||||||
167
src/history.py
Normal file
167
src/history.py
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
"""
|
||||||
|
CProof plugin to read full chat history with custom editor using /hh command.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import prof
|
||||||
|
import re
|
||||||
|
import sqlite3
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
_editor = ""
|
||||||
|
_current_user = ""
|
||||||
|
_logs_dir = ""
|
||||||
|
_db_file = ""
|
||||||
|
_win = "History"
|
||||||
|
_plugin_name = __file__.split('/')[-1] if __file__ else "history.py"
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_win_input():
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _create_win(win):
|
||||||
|
if not prof.win_exists(win):
|
||||||
|
prof.win_create(win, _handle_win_input)
|
||||||
|
|
||||||
|
|
||||||
|
def _show_error(error):
|
||||||
|
error_msg = f"[History Reader] Error happened: {error}"
|
||||||
|
prof.cons_alert()
|
||||||
|
prof.cons_show(error_msg)
|
||||||
|
prof.log_error(error_msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def _str_sanitize(text):
|
||||||
|
return re.sub('[^a-zA-Z0-9\._]', '', text.replace("@", "_at_"))
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_editor(*args):
|
||||||
|
global _editor
|
||||||
|
_db_connection = sqlite3.connect(f"{_db_file}")
|
||||||
|
_db_connection.text_factory = bytes
|
||||||
|
_cur = _db_connection.cursor()
|
||||||
|
msg_buffer = []
|
||||||
|
if args and args[0] == "set":
|
||||||
|
if len(args) < 2:
|
||||||
|
prof.cons_show("Please, use this format: \"/hh set <editor>\"")
|
||||||
|
return
|
||||||
|
_editor = args[1]
|
||||||
|
prof.settings_string_set("history", "editor", _editor)
|
||||||
|
prof.cons_show(
|
||||||
|
f"New editor set up successfully. New editor: {_editor}")
|
||||||
|
return
|
||||||
|
if args and args[0] == "--no-repeat":
|
||||||
|
prof.cons_show("[History Reader] Trying operation again...")
|
||||||
|
if not _current_user:
|
||||||
|
if args and args[0] == "--no-repeat":
|
||||||
|
_show_error("Can't fetch current user.")
|
||||||
|
return
|
||||||
|
prof.send_line(f"/plugins reload {_plugin_name}")
|
||||||
|
prof.send_line("/hh --no-repeat")
|
||||||
|
return
|
||||||
|
if not _editor:
|
||||||
|
prof.cons_show(
|
||||||
|
"Please, set up editor using /hh set. E.g. /hh set /usr/bin/vim")
|
||||||
|
return
|
||||||
|
if not (recipient := prof.get_current_recipient()):
|
||||||
|
prof.cons_show("Please, use this command in a chat window")
|
||||||
|
return
|
||||||
|
|
||||||
|
tmpfpath = _logs_dir / f"{_str_sanitize(recipient)}.log"
|
||||||
|
res = _cur.execute("""SELECT timestamp, from_jid, message FROM `chatlogs`
|
||||||
|
WHERE ((`from_jid` = :jid AND `to_jid` = :myjid)
|
||||||
|
OR (`from_jid` = :myjid AND `to_jid` = :jid))
|
||||||
|
ORDER BY id""", {"jid": recipient, "myjid": _current_user})
|
||||||
|
|
||||||
|
for bmsg in res.fetchall():
|
||||||
|
try:
|
||||||
|
msg = [x.decode("UTF-8", errors="backslashreplace") for x in bmsg]
|
||||||
|
except Exception as e:
|
||||||
|
msg = [x.decode("UTF-8", errors="replace") for x in bmsg]
|
||||||
|
sender = "me" if msg[1] == _current_user else msg[1]
|
||||||
|
msg_buffer.append(f"{msg[0]} - {sender}: {msg[2]}")
|
||||||
|
|
||||||
|
tmpfpath.write_text('\n'.join(msg_buffer),
|
||||||
|
encoding="UTF-8", errors="replace")
|
||||||
|
|
||||||
|
pid = os.fork()
|
||||||
|
if pid == 0:
|
||||||
|
os.execlp(_editor, _editor, str(tmpfpath))
|
||||||
|
else:
|
||||||
|
if pid == -1:
|
||||||
|
return
|
||||||
|
os.waitpid(pid, 0)
|
||||||
|
prof.send_line("/statusbar show name")
|
||||||
|
try:
|
||||||
|
tmpfpath.unlink()
|
||||||
|
except Exception as e:
|
||||||
|
prof.log_error(
|
||||||
|
f"[History Reader] Error on file deletion (path: {tmpfpath}): {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_connect(account_name, fulljid):
|
||||||
|
prof.log_debug(
|
||||||
|
f"[History Reader] prof_on_connect called with this JID: {fulljid}")
|
||||||
|
_init(fulljid)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_disconnect(account_name, fulljid):
|
||||||
|
prof.log_debug(
|
||||||
|
f"[History Reader] prof_on_disconnect called with this JID: {fulljid}")
|
||||||
|
global _current_user
|
||||||
|
_current_user = ""
|
||||||
|
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
prof.log_debug(
|
||||||
|
f"[History Reader] prof_init called with this JID: {fulljid}")
|
||||||
|
_init(fulljid)
|
||||||
|
synopsis = ["/hh"]
|
||||||
|
description = "Open an editor and check user's history."
|
||||||
|
args = [
|
||||||
|
["set", "Set custom editor."]
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/hh",
|
||||||
|
"/hh set /usr/bin/vim",
|
||||||
|
"/hh set gtk-open"
|
||||||
|
]
|
||||||
|
prof.register_command("/hh", 0, 2, synopsis,
|
||||||
|
description, args, examples, _cmd_editor)
|
||||||
|
prof.completer_add("/hh", ["set"])
|
||||||
|
prof.filepath_completer_add("/hh set")
|
||||||
|
|
||||||
|
|
||||||
|
def _init(fulljid):
|
||||||
|
global _current_user, _editor, _logs_dir, _db_file
|
||||||
|
prof.log_debug(
|
||||||
|
f"[History Reader] Initialization started with this JID: {fulljid}")
|
||||||
|
_current_user = fulljid and fulljid.split('/')[0]
|
||||||
|
if not _current_user:
|
||||||
|
prof.log_debug(
|
||||||
|
"[History Reader] Can't fetch current user, aborting initialization...")
|
||||||
|
return
|
||||||
|
_cproof_home = Path(os.getenv('XDG_DATA_HOME')
|
||||||
|
or "~/.local/share").expanduser() / "profanity"
|
||||||
|
_logs_dir = _cproof_home / "chatlogs" / _str_sanitize(_current_user)
|
||||||
|
db_dir = _cproof_home / "database" / _str_sanitize(_current_user)
|
||||||
|
if not _logs_dir.is_dir():
|
||||||
|
_show_error(f"Can't open logs directory. Path: {_logs_dir}")
|
||||||
|
return
|
||||||
|
if not db_dir.is_dir():
|
||||||
|
_show_error(f"Can't open DB directory. Path: {db_dir}")
|
||||||
|
return
|
||||||
|
_db_file = db_dir / "chatlog.db"
|
||||||
|
if not _db_file.is_file():
|
||||||
|
_show_error(f"Log db is not present. Path: {_db_file}")
|
||||||
|
return
|
||||||
|
_editor = prof.settings_string_get("history", "editor", "")
|
||||||
|
if not _editor:
|
||||||
|
prof.cons_show("Please, set up editor using /hh set.")
|
||||||
|
else:
|
||||||
|
prof.cons_show(
|
||||||
|
f"[History Reader] Successfully started. Editor: {_editor}")
|
||||||
47
src/htmlstrip.py
Normal file
47
src/htmlstrip.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
# vim: set ts=2 sw=2 sts=2 et:
|
||||||
|
"""
|
||||||
|
Removes "unwanted" HTML tags from incoming messages and unescapes html.
|
||||||
|
|
||||||
|
Author: Diego Blanco <diego.blanco@treitos.com>
|
||||||
|
|
||||||
|
Some XMPP clients like Adium or Pidgin send HTML tags like <font>, <b>, <u>, etc
|
||||||
|
to format text, specially when using OTR. This plugin removes them and also
|
||||||
|
unescapes HTML like <, >, etc that these clients also tend to escape.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import prof
|
||||||
|
import html
|
||||||
|
|
||||||
|
#( regular expressions
|
||||||
|
re_font = re.compile('</?FONT(>| [^>]+>)', re.IGNORECASE)
|
||||||
|
re_br = re.compile('</?BR>', re.IGNORECASE)
|
||||||
|
re_styles = re.compile('</?(U|B|I)>', re.IGNORECASE)
|
||||||
|
re_link = re.compile('</?a(>| [^>]+>)', re.IGNORECASE)
|
||||||
|
#)
|
||||||
|
|
||||||
|
def _htmlstrip(message):
|
||||||
|
""" Cleans message
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
_message = message
|
||||||
|
_message = re_styles.sub( '', _message )
|
||||||
|
_message = re_font.sub( '', _message )
|
||||||
|
_message = re_br.sub( '\n', _message )
|
||||||
|
_message = re_link.sub( '', _message )
|
||||||
|
|
||||||
|
_message = html.unescape( _message )
|
||||||
|
except:
|
||||||
|
return ("ERR@htmlstrip.py: " + message)
|
||||||
|
finally:
|
||||||
|
return (_message)
|
||||||
|
|
||||||
|
def prof_pre_chat_message_display(barejid, resource, message):
|
||||||
|
return _htmlstrip(message)
|
||||||
|
|
||||||
|
def prof_pre_room_message_display(barejid, nick, message):
|
||||||
|
return _htmlstrip(message)
|
||||||
|
|
||||||
|
def prof_pre_priv_message_display(barejid, nick, message):
|
||||||
|
return _htmlstrip(message)
|
||||||
61
src/imgur.py
Normal file
61
src/imgur.py
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
"""
|
||||||
|
Requires imgur API
|
||||||
|
pip install imgurpython
|
||||||
|
Requires scrot installed for screenshot (on linux)
|
||||||
|
sudo apt-get install scrot
|
||||||
|
|
||||||
|
Uses built in screencapture on OSX
|
||||||
|
"""
|
||||||
|
|
||||||
|
import prof
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
from imgurpython import ImgurClient
|
||||||
|
from imgurpython.helpers.error import ImgurClientError
|
||||||
|
|
||||||
|
client_id = '19c4ba3fc2c26ef'
|
||||||
|
client_secret = 'dd5b0918a2f5d36391d574bd2061c50b47bade63'
|
||||||
|
client = ImgurClient(client_id, client_secret)
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_imgur(arg1):
|
||||||
|
if arg1 == "screenshot":
|
||||||
|
file_path = "/tmp/_prof_screenshot.png"
|
||||||
|
if sys.platform == "darwin":
|
||||||
|
subprocess.call("screencapture " + file_path, shell=True)
|
||||||
|
else:
|
||||||
|
subprocess.call("scrot " + file_path, shell=True)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
file_path = path.expanduser(arg1)
|
||||||
|
except IOError as ioe:
|
||||||
|
prof.cons_show('Could not find file at ' + file_path)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
data = client.upload_from_path(file_path, config=None, anon=True)
|
||||||
|
prof.send_line(data['link'])
|
||||||
|
except ImgurClientError as e:
|
||||||
|
prof.log_error('Could not upload to Imgur - ' + e.error_message)
|
||||||
|
prof.log_error('Imgur status code - ' + e.status_code)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
synopsis = [
|
||||||
|
"/imgur <file_path>",
|
||||||
|
"/imgur screenshot"
|
||||||
|
]
|
||||||
|
description = "Upload an image or screenshot to imgur and send the link"
|
||||||
|
args = [
|
||||||
|
[ "<file_path>", "full path to image file" ],
|
||||||
|
[ "screenshot", "upload a full screen capture" ]
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/imgur ~/images/cats.jpg",
|
||||||
|
"/imgur screenshot"
|
||||||
|
]
|
||||||
|
|
||||||
|
prof.register_command("/imgur", 1, 1, synopsis, description, args, examples, _cmd_imgur)
|
||||||
|
prof.completer_add("/imgur", [ "screenshot" ])
|
||||||
|
prof.filepath_completer_add("/imgur")
|
||||||
137
src/notifycmd.py
Normal file
137
src/notifycmd.py
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""
|
||||||
|
Executes a command when a message is received
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016 Oliver Schmidhauser
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import prof
|
||||||
|
from subprocess import Popen
|
||||||
|
import time
|
||||||
|
from sys import platform
|
||||||
|
|
||||||
|
def secure(string):
|
||||||
|
string=string.replace('\\','\\\\')
|
||||||
|
string=string.replace("\"","\\\"")
|
||||||
|
string=string.replace("$","\$")
|
||||||
|
string=string.replace("`","\`")
|
||||||
|
return string
|
||||||
|
|
||||||
|
def notifycmd(sender,message):
|
||||||
|
command = prof.settings_string_get("notifycmd", "command", "")
|
||||||
|
# replace markers with complex strings first to avoid "%%mittens"=>"(%%)mittens"=>"(%m)ittens"=>"<message>ittens" but rather do "(%%)mittens"=>"%mittens"
|
||||||
|
command = command.replace("%%","{percentreplace}")
|
||||||
|
command = command.replace("%s","${senderreplace}")
|
||||||
|
command = command.replace("%m","${messagereplace}")
|
||||||
|
|
||||||
|
|
||||||
|
command = command.replace("{percentreplace}","%")
|
||||||
|
command = "set -f;senderreplace=\"{}\";messagereplace=\"{}\";{}".format(secure(sender),secure(message),command)
|
||||||
|
p = Popen(['sh', '-c', command])
|
||||||
|
|
||||||
|
def prof_post_chat_message_display(barejid, resource, message):
|
||||||
|
enabled = prof.settings_string_get("notifycmd", "enabled", "on")
|
||||||
|
current_recipient = prof.get_current_recipient()
|
||||||
|
if enabled == "on" or (enabled == "active" and current_recipient == barejid):
|
||||||
|
notifycmd(barejid, message)
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def prof_post_room_message_display(barejid, nick, message):
|
||||||
|
enabled = prof.settings_string_get("notifycmd", "enabled", "on")
|
||||||
|
rooms = prof.settings_string_get("notifycmd", "rooms", "mention")
|
||||||
|
current_muc = prof.get_current_muc()
|
||||||
|
mynick = prof.get_room_nick(barejid)
|
||||||
|
# Don't notify for ones own messages
|
||||||
|
if nick != mynick:
|
||||||
|
if rooms == "on":
|
||||||
|
if enabled == "on":
|
||||||
|
notifycmd(nick + " in " + barejid, message)
|
||||||
|
elif enabled == "active" and current_muc == barejid:
|
||||||
|
notifycmd(nick, message)
|
||||||
|
elif rooms == "mention":
|
||||||
|
if mynick in message:
|
||||||
|
if enabled == "on":
|
||||||
|
notifycmd(nick, message)
|
||||||
|
elif enabled == "active" and current_muc == barejid:
|
||||||
|
notifycmd(nick, message)
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def prof_post_priv_message_display(barejid, nick, message):
|
||||||
|
if enabled:
|
||||||
|
notifycmd(nick,message)
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_notifycmd(arg1=None, arg2=None):
|
||||||
|
if arg1 == "on":
|
||||||
|
prof.settings_string_set("notifycmd", "enabled", "on")
|
||||||
|
prof.cons_show("Notifycmd plugin enabled")
|
||||||
|
elif arg1 == "off":
|
||||||
|
prof.settings_string_set("notifycmd", "enabled", "off")
|
||||||
|
prof.cons_show("Notifycmd plugin disabled")
|
||||||
|
elif arg1 == "active":
|
||||||
|
prof.settings_string_set("notifycmd", "enabled", "active")
|
||||||
|
prof.cons_show("Notifycmd plugin enabled for active window only")
|
||||||
|
elif arg1 == "command":
|
||||||
|
if arg2 == None:
|
||||||
|
prof.cons_bad_cmd_usage("/notifycmd")
|
||||||
|
else:
|
||||||
|
prof.settings_string_set("notifycmd", "command", arg2)
|
||||||
|
prof.cons_show("notifycmd plugin command set to: " + arg2)
|
||||||
|
elif arg1 == "rooms":
|
||||||
|
if arg2 == None:
|
||||||
|
prof.cons_bad_cmd_usage("/notifycmd")
|
||||||
|
else:
|
||||||
|
prof.settings_string_set("notifycmd", "rooms", arg2)
|
||||||
|
prof.cons_show("notifycmd plugin notifications for rooms set to: " + arg2)
|
||||||
|
else:
|
||||||
|
enabled = prof.settings_string_get("notifycmd", "enabled", "on")
|
||||||
|
rooms = prof.settings_string_get("notifycmd", "rooms", "mention")
|
||||||
|
command = prof.settings_string_get("notifycmd", "command", "")
|
||||||
|
prof.cons_show("Notifycmd plugin settings:")
|
||||||
|
prof.cons_show("enabled : " + enabled)
|
||||||
|
prof.cons_show("command : " + command)
|
||||||
|
prof.cons_show("rooms : " + rooms)
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
synopsis = [
|
||||||
|
"/notifycmd on|off|active",
|
||||||
|
"/notifycmd command <command>",
|
||||||
|
"/notifycmd rooms on|off|mention"
|
||||||
|
]
|
||||||
|
description = "Executes a command when a message is received"
|
||||||
|
args = [
|
||||||
|
[ "on|off", "Enable/disable notifycmd for all windows" ],
|
||||||
|
[ "active", "Enable notifycmd for active window only" ],
|
||||||
|
[ "command <args>", "Set command to execute. Replaces %s with sender, %m with message and %% with literal %." ],
|
||||||
|
[ "rooms <args>", "Setting for multi-user rooms. Set to 'on', 'off' or 'mention'. If set to mention it will only run it your nick was mentioned." ]
|
||||||
|
]
|
||||||
|
examples = []
|
||||||
|
|
||||||
|
prof.register_command("/notifycmd", 0, 2, synopsis, description, args, examples, _cmd_notifycmd)
|
||||||
|
prof.completer_add("/notifycmd", [ "on", "off","active","command","rooms" ])
|
||||||
|
prof.completer_add("/notifycmd rooms", [ "on", "off", "mention" ])
|
||||||
60
src/paste.py
Normal file
60
src/paste.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
"""
|
||||||
|
Paste the contents of the clipboard when in a chat or room window.
|
||||||
|
|
||||||
|
Dependencies:
|
||||||
|
pip install future
|
||||||
|
sudo apt-get python-tk (or python3-tk)
|
||||||
|
"""
|
||||||
|
|
||||||
|
import prof
|
||||||
|
import tkinter as tk
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_paste(arg1=None, arg2=None):
|
||||||
|
if not arg1:
|
||||||
|
root = tk.Tk(baseName="")
|
||||||
|
root.withdraw()
|
||||||
|
result = root.clipboard_get()
|
||||||
|
newline = prof.settings_boolean_get("paste", "newline", True)
|
||||||
|
if len(result.splitlines()) > 1 and newline:
|
||||||
|
prof.send_line(u'\u000A' + result)
|
||||||
|
else:
|
||||||
|
prof.send_line(result)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "newline":
|
||||||
|
if not arg2:
|
||||||
|
prof.cons_show("")
|
||||||
|
newline = prof.settings_boolean_get("paste", "newline", True)
|
||||||
|
if newline:
|
||||||
|
prof.cons_show("paste.py newline: on")
|
||||||
|
else:
|
||||||
|
prof.cons_show("paste.py newline: off")
|
||||||
|
elif arg2 == "on":
|
||||||
|
prof.settings_boolean_set("paste", "newline", True)
|
||||||
|
prof.cons_show("paste.py newline enabled.")
|
||||||
|
elif arg2 == "off":
|
||||||
|
prof.settings_boolean_set("paste", "newline", False)
|
||||||
|
prof.cons_show("paste.py newline disabled.")
|
||||||
|
else:
|
||||||
|
prof.cons_bad_cmd_usage("/paste")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
prof.cons_bad_cmd_usage("/paste")
|
||||||
|
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
synopsis = [
|
||||||
|
"/paste",
|
||||||
|
"/paste newline on|off"
|
||||||
|
]
|
||||||
|
description = "Paste contents of clipboard."
|
||||||
|
args = [
|
||||||
|
[ "newline on|off", "Send newline before multiline clipboard text, defaults to on" ]
|
||||||
|
]
|
||||||
|
examples = []
|
||||||
|
prof.register_command("/paste", 0, 2, synopsis, description, args, examples, _cmd_paste)
|
||||||
|
prof.completer_add("/paste", [ "newline" ])
|
||||||
|
prof.completer_add("/paste newline", [ "on", "off" ])
|
||||||
164
src/presence_notify.py
Normal file
164
src/presence_notify.py
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
import prof
|
||||||
|
|
||||||
|
online = set()
|
||||||
|
|
||||||
|
def _show_settings():
|
||||||
|
prof.cons_show("")
|
||||||
|
prof.cons_show("Presence notify plugin settings:")
|
||||||
|
|
||||||
|
mode = prof.settings_string_get("presence_notify", "mode", "all")
|
||||||
|
prof.cons_show("Mode: {mode}".format(mode=mode))
|
||||||
|
|
||||||
|
resource = prof.settings_boolean_get("presence_notify", "resource", False)
|
||||||
|
if resource:
|
||||||
|
prof.cons_show("Resource: ON")
|
||||||
|
else:
|
||||||
|
prof.cons_show("Resource: OFF")
|
||||||
|
|
||||||
|
ignored_list = prof.settings_string_list_get("presence_notify", "ignored")
|
||||||
|
if ignored_list and len(ignored_list) > 0:
|
||||||
|
prof.cons_show("Ignored:")
|
||||||
|
for contact in ignored_list:
|
||||||
|
prof.cons_show(" {barejid}".format(barejid=contact))
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_presence_notify(arg1=None, arg2=None, arg3=None):
|
||||||
|
if arg1 == "all":
|
||||||
|
prof.settings_string_set("presence_notify", "mode", "all")
|
||||||
|
prof.cons_show("Notifying on all presence changes")
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "online":
|
||||||
|
prof.settings_string_set("presence_notify", "mode", "online")
|
||||||
|
prof.cons_show("Notifying on online/offline presence changes only")
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "off":
|
||||||
|
prof.settings_string_set("presence_notify", "mode", "off")
|
||||||
|
prof.cons_show("Presence notifications disabled")
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "ignored":
|
||||||
|
if arg2 == "clear":
|
||||||
|
prof.settings_string_list_clear("presence_notify", "ignored")
|
||||||
|
prof.cons_show("Removed all ignored contacts for presence notifications")
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg2 == "add":
|
||||||
|
if not arg3:
|
||||||
|
prof.cons_bad_cmd_usage("/presence_notify")
|
||||||
|
return
|
||||||
|
prof.settings_string_list_add("presence_notify", "ignored", arg3)
|
||||||
|
prof.cons_show("Added {contact} to ignored contacts for presence notifications".format(contact=arg3))
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg2 == "remove":
|
||||||
|
if not arg3:
|
||||||
|
prof.cons_bad_cmd_usage("/presence_notify")
|
||||||
|
return
|
||||||
|
res = prof.settings_string_list_remove("presence_notify", "ignored", arg3)
|
||||||
|
if res:
|
||||||
|
prof.cons_show("Removed {contact} from ignored contacts for presence notifications".format(contact=arg3))
|
||||||
|
else:
|
||||||
|
prof.cons_show("{contact} not in ignore list for presence notiications".format(contact=arg3))
|
||||||
|
return
|
||||||
|
|
||||||
|
prof.cons_bad_cmd_usage("/presence_notify")
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "resource":
|
||||||
|
if arg2 == "on":
|
||||||
|
prof.settings_boolean_set("presence_notify", "resource", True)
|
||||||
|
prof.cons_show("Showing resource in presence notifications")
|
||||||
|
return;
|
||||||
|
if arg2 == "off":
|
||||||
|
prof.settings_boolean_set("presence_notify", "resource", False)
|
||||||
|
prof.cons_show("Hiding resource in presence notifications")
|
||||||
|
return;
|
||||||
|
|
||||||
|
prof.cons_bad_cmd_usage("/presence_notify")
|
||||||
|
return
|
||||||
|
|
||||||
|
_show_settings()
|
||||||
|
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
synopsis = [
|
||||||
|
"/presence_notify all|online|off",
|
||||||
|
"/presence_notify ignored add|remove|clear [<barejid>]",
|
||||||
|
"/presence_notify resource on|off"
|
||||||
|
]
|
||||||
|
description = "Send a desktop notification on presence updates."
|
||||||
|
args = [
|
||||||
|
[ "all", "Enable all presence notifications" ],
|
||||||
|
[ "online", "Enable only online/offline presence notifications" ],
|
||||||
|
[ "off", "Disable presence notifications" ],
|
||||||
|
[ "ignored add|remove <barejid>", "Add or remove a contact from the list excluded from presence notifications"],
|
||||||
|
[ "ignored clear", "Clear the list of excluded contacts"],
|
||||||
|
[ "resource on|off", "Enable/disable showing the contacts resource in the notification"]
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/presence_notify all",
|
||||||
|
"/presence_notify ignored add bob@server.org"
|
||||||
|
]
|
||||||
|
|
||||||
|
prof.register_command("/presence_notify", 0, 3, synopsis, description, args, examples, _cmd_presence_notify)
|
||||||
|
|
||||||
|
prof.completer_add("/presence_notify",
|
||||||
|
[ "all", "online", "off", "ignored", "resource" ]
|
||||||
|
)
|
||||||
|
prof.completer_add("/presence_notify ignored",
|
||||||
|
[ "add", "remove", "clear" ]
|
||||||
|
)
|
||||||
|
prof.completer_add("/presence_notify resource",
|
||||||
|
[ "on", "off" ]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _do_notify(barejid, presence):
|
||||||
|
ignored = prof.settings_string_list_get("presence_notify", "ignored")
|
||||||
|
if ignored and barejid in ignored:
|
||||||
|
return False
|
||||||
|
|
||||||
|
mode = prof.settings_string_get("presence_notify", "mode", "all")
|
||||||
|
if mode == "all":
|
||||||
|
return True
|
||||||
|
elif mode == "online":
|
||||||
|
if barejid in online:
|
||||||
|
if presence == "offline":
|
||||||
|
online.remove(barejid)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
if presence != "offline":
|
||||||
|
online.add(barejid)
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
else: # off
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_contact_presence(barejid, resource, presence, status, priority):
|
||||||
|
if _do_notify(barejid, presence):
|
||||||
|
jid = barejid
|
||||||
|
if prof.settings_boolean_get("presence_notify", "resource", False):
|
||||||
|
jid = jid + "/" + resource
|
||||||
|
message = "{jid} is {presence}".format(jid=jid, presence=presence)
|
||||||
|
if status:
|
||||||
|
message = message + ", \"{status}\"".format(status=status)
|
||||||
|
prof.notify(message, 5000, "Presence")
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_contact_offline(barejid, resource, status):
|
||||||
|
if _do_notify(barejid, "offline"):
|
||||||
|
jid = barejid
|
||||||
|
if prof.settings_boolean_get("presence_notify", "resource", False):
|
||||||
|
jid = jid + "/" + resource
|
||||||
|
message = "{jid} is offline".format(jid=jid)
|
||||||
|
if status:
|
||||||
|
message = message + ", \"{status}\"".format(status=status)
|
||||||
|
prof.notify(message, 5000, "Presence")
|
||||||
|
return
|
||||||
144
src/sanitize.py
Normal file
144
src/sanitize.py
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
"""
|
||||||
|
Sanitize incoming messages from Adium clients.
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2016 Nd2(SO4)3
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from io import StringIO
|
||||||
|
from lxml import etree
|
||||||
|
from lxml.etree import _ElementUnicodeResult, _ElementStringResult
|
||||||
|
import prof
|
||||||
|
|
||||||
|
# ROADMAP
|
||||||
|
#
|
||||||
|
# Version 2:
|
||||||
|
# "/sanitise on|off": global auto detect setting
|
||||||
|
# "/sanitise <jid> on|off|<mode>": setting per JID: can be autodetect, off,
|
||||||
|
# or a special "mode" (if there are any).
|
||||||
|
|
||||||
|
iq_count = 1
|
||||||
|
|
||||||
|
# Stores client information. JID/str~>Client/str.
|
||||||
|
clients = {}
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_presence_stanza_receive(stanza):
|
||||||
|
"""Send a software version request when a contact comes online."""
|
||||||
|
full_jid = etree.fromstring(stanza).get("from")
|
||||||
|
if full_jid:
|
||||||
|
send_version_request(full_jid)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def send_version_request(full_jid):
|
||||||
|
global iq_count
|
||||||
|
|
||||||
|
iq = etree.Element(
|
||||||
|
"iq", {"type": "get", "to": full_jid, "id": "sanitiser_" + str(iq_count)}
|
||||||
|
)
|
||||||
|
etree.SubElement(iq, "query", {"xmlns": "jabber:iq:version"})
|
||||||
|
|
||||||
|
iq_count = iq_count + 1
|
||||||
|
prof.send_stanza(etree.tostring(iq))
|
||||||
|
|
||||||
|
|
||||||
|
def prof_on_iq_stanza_receive(stanza):
|
||||||
|
"""Listen for software version responses and save results in the
|
||||||
|
'clients' store.
|
||||||
|
"""
|
||||||
|
iq = etree.fromstring(stanza)
|
||||||
|
id = iq.get("id")
|
||||||
|
if not id:
|
||||||
|
return True
|
||||||
|
if not id.startswith("sanitiser_"):
|
||||||
|
return True
|
||||||
|
full_jid = iq.get("from")
|
||||||
|
if not full_jid:
|
||||||
|
return False
|
||||||
|
|
||||||
|
query = iq.find("{jabber:iq:version}query")
|
||||||
|
if query is None:
|
||||||
|
return False
|
||||||
|
client = query.find("{jabber:iq:version}name")
|
||||||
|
if client is not None:
|
||||||
|
clients[full_jid] = client.text
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def prof_pre_chat_message_display(jid, resource, message):
|
||||||
|
"""Sanitises chat room messages if necessary."""
|
||||||
|
full_jid = "%s/%s" % (jid, resource)
|
||||||
|
if full_jid not in clients:
|
||||||
|
return message
|
||||||
|
return get_sanitiser(clients[full_jid])(message)
|
||||||
|
|
||||||
|
|
||||||
|
# Sanitiser functions:
|
||||||
|
|
||||||
|
|
||||||
|
def get_sanitiser(client):
|
||||||
|
"""Returns appropriate sanitiser function for the given
|
||||||
|
Jabber client (string).
|
||||||
|
"""
|
||||||
|
if client.startswith("Adium"):
|
||||||
|
return sanitise
|
||||||
|
else:
|
||||||
|
return lambda msg: msg
|
||||||
|
|
||||||
|
|
||||||
|
def sanitise(message):
|
||||||
|
"""Cleans message from HTML. Raises exceptions on problems."""
|
||||||
|
parser = etree.HTMLParser()
|
||||||
|
tree = etree.parse(StringIO(unicode(message)), parser)
|
||||||
|
elems = tree.xpath("(//br|//a|//*[not(self::a)]/text())")
|
||||||
|
return "".join(map(substitude, elems))
|
||||||
|
|
||||||
|
|
||||||
|
def try_sanitise(message):
|
||||||
|
"""Same as 'sanitise' but returns unmodified message if it encounters
|
||||||
|
a problem, instead of throwing an exception.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return sanitise(message)
|
||||||
|
except:
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def substitude(elem):
|
||||||
|
"""Substitudes an lxml element with a string representation."""
|
||||||
|
if type(elem) in (_ElementUnicodeResult, _ElementStringResult):
|
||||||
|
return str(elem)
|
||||||
|
else:
|
||||||
|
if elem.tag == "br":
|
||||||
|
return "\n"
|
||||||
|
elif elem.tag == "a":
|
||||||
|
text = elem.text or ""
|
||||||
|
href = elem.get("href", "")
|
||||||
|
if not text and not href:
|
||||||
|
return ""
|
||||||
|
elif text == href:
|
||||||
|
return href
|
||||||
|
else:
|
||||||
|
return "%s (%s)" % (text, href)
|
||||||
|
else:
|
||||||
|
raise Exception("unhandled tag <%s>" % elem.tag)
|
||||||
@@ -9,36 +9,39 @@ On OSX will use the built in 'say' command.
|
|||||||
|
|
||||||
import prof
|
import prof
|
||||||
import os
|
import os
|
||||||
|
import shlex
|
||||||
from sys import platform
|
from sys import platform
|
||||||
|
|
||||||
def say(message):
|
def say(message):
|
||||||
args = prof.settings_get_string("say", "args", "")
|
args = prof.settings_string_get("say", "args", "")
|
||||||
|
|
||||||
if platform == "darwin":
|
if platform == "darwin":
|
||||||
os.system("say " + args + " '" + message + "' 2>/dev/null")
|
os.system("say " + args + " " + shlex.quote(message) + " 2>/dev/null")
|
||||||
elif platform == "linux" or platform == "linux2":
|
elif platform == "linux" or platform == "linux2":
|
||||||
os.system("echo '" + message + "' | espeak " + args + " 2>/dev/null")
|
os.system("echo " + shlex.quote(message) + " | espeak " + args + " 2>/dev/null")
|
||||||
|
|
||||||
|
|
||||||
def prof_post_chat_message_display(jid, message):
|
def prof_post_chat_message_display(barejid, resource, message):
|
||||||
enabled = prof.settings_get_string("say", "enabled", "off")
|
enabled = prof.settings_string_get("say", "enabled", "off")
|
||||||
current_recipient = prof.get_current_recipient()
|
current_recipient = prof.get_current_recipient()
|
||||||
if enabled == "on" or (enabled == "active" and current_recipient == jid):
|
if enabled == "on" or (enabled == "active" and current_recipient == barejid):
|
||||||
say(jid + " says " + message)
|
say(barejid + " says " + message)
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
||||||
def prof_post_room_message_display(room, nick, message):
|
def prof_post_room_message_display(barejid, nick, message):
|
||||||
enabled = prof.settings_get_string("say", "enabled", "off")
|
enabled = prof.settings_string_get("say", "enabled", "off")
|
||||||
current_muc = prof.get_current_muc()
|
current_muc = prof.get_current_muc()
|
||||||
if enabled == "on" or (enable == "active" and current_muc == jid):
|
if enabled == "on":
|
||||||
say(nick + " says " + message + " in " + room)
|
say(nick + " in " + barejid + " says " + message)
|
||||||
|
elif enabled == "active" and current_muc == barejid:
|
||||||
|
say(nick + " says " + message)
|
||||||
|
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
||||||
def prof_post_priv_message_display(room, nick, message):
|
def prof_post_priv_message_display(barejid, nick, message):
|
||||||
# TODO add get current nick hook for private chats
|
# TODO add get current nick hook for private chats
|
||||||
if enabled:
|
if enabled:
|
||||||
say(nick + " says " + message)
|
say(nick + " says " + message)
|
||||||
@@ -48,22 +51,22 @@ def prof_post_priv_message_display(room, nick, message):
|
|||||||
|
|
||||||
def _cmd_say(arg1=None, arg2=None):
|
def _cmd_say(arg1=None, arg2=None):
|
||||||
if arg1 == "on":
|
if arg1 == "on":
|
||||||
prof.settings_set_string("say", "enabled", "on")
|
prof.settings_string_set("say", "enabled", "on")
|
||||||
prof.cons_show("Say plugin enabled")
|
prof.cons_show("Say plugin enabled")
|
||||||
elif arg1 == "off":
|
elif arg1 == "off":
|
||||||
prof.settings_set_string("say", "enabled", "off")
|
prof.settings_string_set("say", "enabled", "off")
|
||||||
prof.cons_show("Say plugin disabled")
|
prof.cons_show("Say plugin disabled")
|
||||||
elif arg1 == "active":
|
elif arg1 == "active":
|
||||||
prof.settings_set_string("say", "enabled", "active")
|
prof.settings_string_set("say", "enabled", "active")
|
||||||
prof.cons_show("Say plugin enabled for active window only")
|
prof.cons_show("Say plugin enabled for active window only")
|
||||||
elif arg1 == "args":
|
elif arg1 == "args":
|
||||||
if arg2 == None:
|
if arg2 == None:
|
||||||
prof.cons_bad_cmd_usage("/say")
|
prof.cons_bad_cmd_usage("/say")
|
||||||
else:
|
else:
|
||||||
prof.settings_set_string("say", "args", arg2)
|
prof.settings_string_set("say", "args", arg2)
|
||||||
prof.cons_show("Say plugin arguments set to: " + arg2)
|
prof.cons_show("Say plugin arguments set to: " + arg2)
|
||||||
elif arg1 == "clearargs":
|
elif arg1 == "clearargs":
|
||||||
prof.settings_set_string("say", "args", "")
|
prof.settings_string_set("say", "args", "")
|
||||||
prof.cons_show("Say plugin arguments cleared")
|
prof.cons_show("Say plugin arguments cleared")
|
||||||
elif arg1 == "test":
|
elif arg1 == "test":
|
||||||
if arg2 == None:
|
if arg2 == None:
|
||||||
@@ -71,8 +74,8 @@ def _cmd_say(arg1=None, arg2=None):
|
|||||||
else:
|
else:
|
||||||
say(arg2)
|
say(arg2)
|
||||||
else:
|
else:
|
||||||
enabled = prof.settings_get_string("say", "enabled", "off")
|
enabled = prof.settings_string_get("say", "enabled", "off")
|
||||||
args = prof.settings_get_string("say", "args", "")
|
args = prof.settings_string_get("say", "args", "")
|
||||||
prof.cons_show("Say plugin settings:")
|
prof.cons_show("Say plugin settings:")
|
||||||
prof.cons_show("enabled : " + enabled)
|
prof.cons_show("enabled : " + enabled)
|
||||||
if args != "":
|
if args != "":
|
||||||
@@ -86,7 +89,7 @@ def prof_init(version, status, account_name, fulljid):
|
|||||||
"/say clearargs",
|
"/say clearargs",
|
||||||
"/say test <message>"
|
"/say test <message>"
|
||||||
]
|
]
|
||||||
description = "Read all messages out loud"
|
description = "Read messages out loud"
|
||||||
args = [
|
args = [
|
||||||
[ "on|off", "Enable/disable say for all windows" ],
|
[ "on|off", "Enable/disable say for all windows" ],
|
||||||
[ "active", "Enable say for active window only" ],
|
[ "active", "Enable say for active window only" ],
|
||||||
128
src/shortcuts.py
Normal file
128
src/shortcuts.py
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""
|
||||||
|
Manage Message Shortcuts
|
||||||
|
|
||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2016 René Calles
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import prof
|
||||||
|
|
||||||
|
ENABLED = True
|
||||||
|
SHORTCUTS_DICTIONARY = {u'shrug': u'¯\_(ツ)_/¯',
|
||||||
|
u'yay': u'\o/'}
|
||||||
|
|
||||||
|
plugin_win = "Shortcuts"
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_win_input(win, line):
|
||||||
|
prof.win_show(win, line)
|
||||||
|
|
||||||
|
|
||||||
|
def create_win():
|
||||||
|
if prof.win_exists(plugin_win) == False:
|
||||||
|
prof.win_create(plugin_win, _handle_win_input)
|
||||||
|
|
||||||
|
|
||||||
|
def _substitute(message):
|
||||||
|
if ENABLED:
|
||||||
|
shortcuts = re.findall(r'(?:^|\s)(:\w+:)(?=\s|$)', message)
|
||||||
|
for s in shortcuts:
|
||||||
|
shortcut_text = SHORTCUTS_DICTIONARY.get(s.strip()[1:-1])
|
||||||
|
if shortcut_text:
|
||||||
|
message = message.replace(s.strip(), shortcut_text)
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def save(key, value):
|
||||||
|
global SHORTCUTS_DICTIONARY
|
||||||
|
SHORTCUTS_DICTIONARY[key] = value
|
||||||
|
|
||||||
|
|
||||||
|
def _list_shortcuts():
|
||||||
|
global SHORTCUTS_DICTIONARY
|
||||||
|
# ordered_dict = sorted(DICTIONARY.items(), key=lambda t: t[0])
|
||||||
|
prof.cons_show(u'Shortcuts: ')
|
||||||
|
for key, value in SHORTCUTS_DICTIONARY.iteritems():
|
||||||
|
prof.cons_show(u':{0}: => {1}'.format(key, value))
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_shortcuts(arg1=None, arg2=None, arg3=None):
|
||||||
|
global ENABLED
|
||||||
|
|
||||||
|
if arg1 == None:
|
||||||
|
prof.cons_show("Shortcuts Plugin is {}.".format("ON" if ENABLED else "OFF"))
|
||||||
|
elif arg1 == "on":
|
||||||
|
ENABLED = True
|
||||||
|
elif arg1 == "off":
|
||||||
|
ENABLED = False
|
||||||
|
elif arg1 == "list":
|
||||||
|
_list_shortcuts()
|
||||||
|
elif arg1 == "set":
|
||||||
|
if arg2 == None:
|
||||||
|
prof.cons_bad_cmd_usage("/shortcuts")
|
||||||
|
else:
|
||||||
|
save(arg2, arg3)
|
||||||
|
else:
|
||||||
|
prof.cons_bad_cmd_usage("/shortcuts")
|
||||||
|
|
||||||
|
|
||||||
|
def prof_pre_chat_message_send(jid, message):
|
||||||
|
return _substitute(message)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_pre_room_message_send(room, message):
|
||||||
|
return _substitute(message)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_pre_priv_message_send(room, nick, message):
|
||||||
|
return _substitute(message)
|
||||||
|
|
||||||
|
|
||||||
|
def prof_init(version, status):
|
||||||
|
synopsis = [
|
||||||
|
"/shortcuts",
|
||||||
|
"/shortcuts on|off",
|
||||||
|
"/shortcuts set <name> <text>"
|
||||||
|
]
|
||||||
|
description = "Manage shortcuts for emoticons or other stuff"
|
||||||
|
args = [
|
||||||
|
[ "on|off", "Enable/disable shortcuts" ],
|
||||||
|
[ "set <name> <text>", "Save shortcut" ],
|
||||||
|
[ "list", "List Shortcuts Dictionary"]
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/shortcuts",
|
||||||
|
"/shortcuts on",
|
||||||
|
"/shortcuts set lol \"Laughing out loud\""
|
||||||
|
]
|
||||||
|
|
||||||
|
prof.register_command("/shortcuts", 0, 3, synopsis, description, args, examples, _cmd_shortcuts)
|
||||||
|
prof.register_ac("/shortcuts", [ "on", "off", "set" ])
|
||||||
|
|
||||||
|
shortcut_keys = [":{}:".format(k) for k in SHORTCUTS_DICTIONARY.keys()]
|
||||||
|
# prof.cons_show(", ".join(shortcut_keys))
|
||||||
|
prof.register_ac(" ", shortcut_keys)
|
||||||
313
src/sounds.py
Normal file
313
src/sounds.py
Normal file
@@ -0,0 +1,313 @@
|
|||||||
|
"""
|
||||||
|
Play sounds on receiving messages.
|
||||||
|
|
||||||
|
Default settings require mpg123 to be installed on the host system:
|
||||||
|
sudo apt-get install mpg123
|
||||||
|
brew install mpg123
|
||||||
|
"""
|
||||||
|
|
||||||
|
from functools import lru_cache
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Tuple
|
||||||
|
|
||||||
|
import prof
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
|
||||||
|
_last_played = {}
|
||||||
|
|
||||||
|
|
||||||
|
@lru_cache(maxsize=16)
|
||||||
|
def get_expanded_path(path_str: str) -> Tuple[Path, str]:
|
||||||
|
path = Path(path_str).expanduser()
|
||||||
|
return path, str(path)
|
||||||
|
|
||||||
|
|
||||||
|
def _play_sound_file(soundfile: str):
|
||||||
|
soundfile_path, soundfile_str = get_expanded_path(soundfile)
|
||||||
|
|
||||||
|
if not soundfile_path.exists():
|
||||||
|
prof.cons_show(f"Sound file not found: {soundfile_str}")
|
||||||
|
return
|
||||||
|
|
||||||
|
now = time.monotonic()
|
||||||
|
if _last_played.get(soundfile_str, 0) + 0.5 > now:
|
||||||
|
return # skip if played too recently
|
||||||
|
_last_played[soundfile_str] = now
|
||||||
|
|
||||||
|
audioplayer = prof.settings_string_get("sounds", "audioplayer", "mpg123 -q")
|
||||||
|
subprocess.Popen([*audioplayer.split(), soundfile_str], start_new_session=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _play_sound(kind: str = "chat"):
|
||||||
|
soundfile = prof.settings_string_get("sounds", kind, None)
|
||||||
|
if soundfile:
|
||||||
|
_play_sound_file(soundfile)
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_sounds(arg1=None, arg2=None, arg3=None):
|
||||||
|
if not arg1:
|
||||||
|
prof.cons_show("")
|
||||||
|
enabled = prof.settings_boolean_get("sounds", "enabled", False)
|
||||||
|
chatsound = prof.settings_string_get("sounds", "chat", None)
|
||||||
|
roomsound = prof.settings_string_get("sounds", "room", None)
|
||||||
|
privatesound = prof.settings_string_get("sounds", "private", None)
|
||||||
|
roomlist = prof.settings_string_list_get("sounds", "rooms")
|
||||||
|
audioplayer = prof.settings_string_get("sounds", "audioplayer", "mpg123 -q")
|
||||||
|
|
||||||
|
if chatsound or roomsound or privatesound:
|
||||||
|
if enabled:
|
||||||
|
prof.cons_show("Sounds: ON")
|
||||||
|
else:
|
||||||
|
prof.cons_show("Sounds: OFF")
|
||||||
|
|
||||||
|
prof.cons_show("Audio Player: " + audioplayer)
|
||||||
|
if chatsound:
|
||||||
|
prof.cons_show(" Chat : " + chatsound)
|
||||||
|
if roomsound:
|
||||||
|
prof.cons_show(" Room : " + roomsound)
|
||||||
|
if roomlist and len(roomlist) > 0:
|
||||||
|
for room in roomlist:
|
||||||
|
prof.cons_show(" " + room)
|
||||||
|
else:
|
||||||
|
prof.cons_show(" All rooms")
|
||||||
|
if privatesound:
|
||||||
|
prof.cons_show(" Private : " + privatesound)
|
||||||
|
|
||||||
|
else:
|
||||||
|
prof.cons_show("No sounds set.")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "on":
|
||||||
|
prof.settings_boolean_set("sounds", "enabled", True)
|
||||||
|
prof.cons_show("Sounds enabled")
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "off":
|
||||||
|
prof.settings_boolean_set("sounds", "enabled", False)
|
||||||
|
prof.cons_show("Sounds disabled")
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "test":
|
||||||
|
if arg2 not in (
|
||||||
|
"chat",
|
||||||
|
"private",
|
||||||
|
"room",
|
||||||
|
):
|
||||||
|
prof.cons_bad_cmd_usage("/sounds")
|
||||||
|
return
|
||||||
|
|
||||||
|
enabled = prof.settings_boolean_get("sounds", "enabled", False)
|
||||||
|
if not enabled:
|
||||||
|
prof.cons_show("Sounds disabled")
|
||||||
|
return
|
||||||
|
|
||||||
|
soundfile = prof.settings_string_get("sounds", arg2, None)
|
||||||
|
if not soundfile:
|
||||||
|
prof.cons_show("No sound file for " + arg2)
|
||||||
|
return
|
||||||
|
|
||||||
|
_play_sound(kind=arg2)
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "set":
|
||||||
|
if arg2 == "chat":
|
||||||
|
prof.settings_string_set("sounds", "chat", arg3)
|
||||||
|
prof.cons_show("Set chat sound: " + arg3)
|
||||||
|
elif arg2 == "room":
|
||||||
|
prof.settings_string_set("sounds", "room", arg3)
|
||||||
|
prof.cons_show("Set room sound: " + arg3)
|
||||||
|
elif arg2 == "private":
|
||||||
|
prof.settings_string_set("sounds", "private", arg3)
|
||||||
|
prof.cons_show("Set private sound: " + arg3)
|
||||||
|
elif arg2 == "audioplayer":
|
||||||
|
prof.settings_string_set("sounds", "audioplayer", arg3)
|
||||||
|
prof.cons_show("Set audio player: " + arg3)
|
||||||
|
else:
|
||||||
|
prof.cons_bad_cmd_usage("/sounds")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "reset":
|
||||||
|
if arg2 == "audioplayer":
|
||||||
|
prof.settings_string_set("sounds", "audioplayer", "mpg123 -q")
|
||||||
|
prof.cons_show("Reset audio player to default.")
|
||||||
|
else:
|
||||||
|
prof.cons_bad_cmd_usage("/sounds")
|
||||||
|
|
||||||
|
if arg1 == "clear":
|
||||||
|
if arg2 == "chat":
|
||||||
|
prof.settings_string_set("sounds", "chat", "")
|
||||||
|
prof.cons_show("Removed chat sound.")
|
||||||
|
elif arg2 == "room":
|
||||||
|
prof.settings_string_set("sounds", "room", "")
|
||||||
|
prof.cons_show("Removed room sound.")
|
||||||
|
elif arg2 == "private":
|
||||||
|
prof.settings_string_set("sounds", "private", "")
|
||||||
|
prof.cons_show("Removed private sound.")
|
||||||
|
else:
|
||||||
|
prof.cons_bad_cmd_usage("/sounds")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "rooms":
|
||||||
|
if arg2 == "add":
|
||||||
|
if not arg3:
|
||||||
|
prof.cons_bad_cmd_usage("/sounds")
|
||||||
|
else:
|
||||||
|
prof.settings_string_list_add("sounds", "rooms", arg3)
|
||||||
|
prof.cons_show("Sounds enabled for room: " + arg3)
|
||||||
|
elif arg2 == "remove":
|
||||||
|
if not arg3:
|
||||||
|
prof.cons_bad_cmd_usage("/sounds")
|
||||||
|
else:
|
||||||
|
prof.settings_string_list_remove("sounds", "rooms", arg3)
|
||||||
|
roomlist = prof.settings_string_list_get("sounds", "rooms")
|
||||||
|
if roomlist and len(roomlist) > 0:
|
||||||
|
prof.cons_show("Sounds disabled for room: " + arg3)
|
||||||
|
else:
|
||||||
|
prof.cons_show("Empty room list for sounds, playing in all rooms.")
|
||||||
|
elif arg2 == "clear":
|
||||||
|
prof.settings_string_list_clear("sounds", "rooms")
|
||||||
|
prof.cons_show("Cleared sounds room list, playing in all rooms.")
|
||||||
|
else:
|
||||||
|
prof.cons_bad_cmd_usage("/sounds")
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "mute":
|
||||||
|
if not arg2:
|
||||||
|
prof.cons_bad_cmd_usage("/sounds mute <jid>")
|
||||||
|
else:
|
||||||
|
prof.settings_string_list_add("sounds", "muted", arg2)
|
||||||
|
prof.cons_show("Muted JID: " + arg2)
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "unmute":
|
||||||
|
if not arg2:
|
||||||
|
prof.cons_bad_cmd_usage("/sounds unmute <jid>")
|
||||||
|
else:
|
||||||
|
prof.settings_string_list_remove("sounds", "muted", arg2)
|
||||||
|
prof.cons_show("Unmuted JID: " + arg2)
|
||||||
|
return
|
||||||
|
|
||||||
|
prof.cons_bad_cmd_usage("/sounds")
|
||||||
|
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
synopsis = [
|
||||||
|
"/sounds",
|
||||||
|
"/sounds on|off",
|
||||||
|
"/sounds set audioplayer <cmd>",
|
||||||
|
"/sounds reset audioplayer",
|
||||||
|
"/sounds set chat <file>",
|
||||||
|
"/sounds set room <file>",
|
||||||
|
"/sounds set private <file>",
|
||||||
|
"/sounds test private|room|chat",
|
||||||
|
"/sounds clear chat",
|
||||||
|
"/sounds clear room",
|
||||||
|
"/sounds clear private",
|
||||||
|
"/sounds rooms add <roomjid>",
|
||||||
|
]
|
||||||
|
description = "Play sounds on receiving messages. Executing the command without arguments displays current settings."
|
||||||
|
args = [
|
||||||
|
["on|off", "Enable or disable playing sounds."],
|
||||||
|
[
|
||||||
|
"set audioplayer <cmd>",
|
||||||
|
"Commmand line of audio player to use for playing sound files. Defaults to mpg123.",
|
||||||
|
],
|
||||||
|
["reset audioplayer", "Resets the audio player to the default mpg123."],
|
||||||
|
["set chat <file>", "Path to sound file to play on chat messages."],
|
||||||
|
["set room <file>", "Path to sound file to play on room messages."],
|
||||||
|
["set private <file>", "Path to sound file to play on private room messages."],
|
||||||
|
["test private|room|chat", "Test the configured audio player and sound file."],
|
||||||
|
["clear chat", "Remove the sound for chat messages."],
|
||||||
|
["clear room", "Remove the sound for room messages."],
|
||||||
|
["clear private", "Remove the sound for private messages."],
|
||||||
|
[
|
||||||
|
"rooms add <roomjid>",
|
||||||
|
"Add the room to the list that will play the room sound.",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"rooms remove <roomjid>",
|
||||||
|
"Remove the room from the list that will play the room sound.",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"rooms clear",
|
||||||
|
"Clear the room list, all rooms will play sounds on new messages.",
|
||||||
|
],
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/sounds set audioplayer paplay",
|
||||||
|
"/sounds set chat ~/sounds/woof.mp3",
|
||||||
|
"/sounds set room ~/sounds/meow.mp3",
|
||||||
|
"/sounds set private ~/sounds/shhh.mp3",
|
||||||
|
"/sounds test private",
|
||||||
|
"/sounds remove private",
|
||||||
|
"/sounds rooms add myroom@conference.server.org",
|
||||||
|
"/sounds on",
|
||||||
|
]
|
||||||
|
|
||||||
|
prof.register_command(
|
||||||
|
"/sounds", 0, 3, synopsis, description, args, examples, _cmd_sounds
|
||||||
|
)
|
||||||
|
|
||||||
|
prof.completer_add(
|
||||||
|
"/sounds", ["set", "clear", "on", "off", "rooms", "reset", "mute", "unmute"]
|
||||||
|
)
|
||||||
|
prof.completer_add("/sounds set", ["chat", "room", "private", "audioplayer"])
|
||||||
|
prof.completer_add("/sounds reset", ["audioplayer"])
|
||||||
|
prof.completer_add("/sounds test", ["chat", "room", "private"])
|
||||||
|
prof.completer_add("/sounds clear", ["chat", "room", "private"])
|
||||||
|
prof.completer_add("/sounds rooms", ["add", "remove", "clear"])
|
||||||
|
prof.filepath_completer_add("/sounds set chat")
|
||||||
|
prof.filepath_completer_add("/sounds set room")
|
||||||
|
prof.filepath_completer_add("/sounds set private")
|
||||||
|
|
||||||
|
|
||||||
|
def prof_post_chat_message_display(barejid, resource, message):
|
||||||
|
enabled = prof.settings_boolean_get("sounds", "enabled", False)
|
||||||
|
if not enabled:
|
||||||
|
return
|
||||||
|
|
||||||
|
muted = prof.settings_string_list_get("sounds", "muted")
|
||||||
|
if muted and barejid in muted:
|
||||||
|
return
|
||||||
|
|
||||||
|
_play_sound(kind="chat")
|
||||||
|
|
||||||
|
|
||||||
|
def prof_post_room_message_display(barejid, nick, message):
|
||||||
|
my_nick = prof.get_room_nick(barejid)
|
||||||
|
if not my_nick:
|
||||||
|
return
|
||||||
|
|
||||||
|
if my_nick == nick:
|
||||||
|
return
|
||||||
|
|
||||||
|
enabled = prof.settings_boolean_get("sounds", "enabled", False)
|
||||||
|
if not enabled:
|
||||||
|
return
|
||||||
|
|
||||||
|
roomlist = prof.settings_string_list_get("sounds", "rooms")
|
||||||
|
if roomlist and (barejid not in roomlist):
|
||||||
|
return
|
||||||
|
|
||||||
|
muted = prof.settings_string_list_get("sounds", "muted")
|
||||||
|
if muted and barejid in muted:
|
||||||
|
return
|
||||||
|
|
||||||
|
_play_sound(soundfile, kind="room")
|
||||||
|
|
||||||
|
|
||||||
|
def prof_post_priv_message_display(barejid, nick, message):
|
||||||
|
enabled = prof.settings_boolean_get("sounds", "enabled", False)
|
||||||
|
if not enabled:
|
||||||
|
return
|
||||||
|
|
||||||
|
muted = prof.settings_string_list_get("sounds", "muted")
|
||||||
|
if muted and barejid in muted:
|
||||||
|
return
|
||||||
|
|
||||||
|
_play_sound(kind="private")
|
||||||
129
src/syscmd.py
Normal file
129
src/syscmd.py
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
"""
|
||||||
|
Allow running system commands in a plugin window, or send result to recipient
|
||||||
|
|
||||||
|
Theme options in ~/.local/share/profanity/plugin_themes
|
||||||
|
|
||||||
|
[system]
|
||||||
|
command=magenta
|
||||||
|
result=green
|
||||||
|
"""
|
||||||
|
|
||||||
|
import prof
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
system_win = "System"
|
||||||
|
|
||||||
|
|
||||||
|
def _get_result(command):
|
||||||
|
return subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout.read()
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_win_input(win, command):
|
||||||
|
prof.win_show_themed(win, "system", "command", None, command)
|
||||||
|
prof.win_show(win, "")
|
||||||
|
result = _get_result(command)
|
||||||
|
split = result.splitlines()
|
||||||
|
for s in split:
|
||||||
|
prof.win_show_themed(win, "system", "result", None, s)
|
||||||
|
prof.win_show(win, "")
|
||||||
|
|
||||||
|
|
||||||
|
def create_win():
|
||||||
|
if prof.win_exists(system_win) == False:
|
||||||
|
prof.win_create(system_win, _handle_win_input)
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_send(command=None):
|
||||||
|
if command == None:
|
||||||
|
prof.cons_bad_cmd_usage("/system")
|
||||||
|
return
|
||||||
|
|
||||||
|
room = prof.get_current_muc()
|
||||||
|
recipient = prof.get_current_recipient()
|
||||||
|
if room == None and recipient == None:
|
||||||
|
prof.cons_show("You must be in a chat or muc window to send a system command")
|
||||||
|
prof.cons_alert()
|
||||||
|
return
|
||||||
|
|
||||||
|
result = _get_result(command)
|
||||||
|
newline = prof.settings_boolean_get("system", "newline", True)
|
||||||
|
if len(result.splitlines()) > 1 and newline:
|
||||||
|
prof.send_line(u'\u000A' + result.decode('utf-8', errors='ignore'))
|
||||||
|
else:
|
||||||
|
prof.send_line(result)
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_exec(command=None):
|
||||||
|
if command == None:
|
||||||
|
prof.cons_bad_cmd_usage("/system")
|
||||||
|
return;
|
||||||
|
|
||||||
|
create_win()
|
||||||
|
prof.win_focus(system_win)
|
||||||
|
_handle_win_input(system_win, command)
|
||||||
|
|
||||||
|
|
||||||
|
def _handle_newline(setting=None):
|
||||||
|
if not setting:
|
||||||
|
prof.cons_show("")
|
||||||
|
newline = prof.settings_boolean_get("system", "newline", True)
|
||||||
|
if newline:
|
||||||
|
prof.cons_show("syscmd.py newline: on")
|
||||||
|
else:
|
||||||
|
prof.cons_show("syscmd.py newline: off")
|
||||||
|
return
|
||||||
|
|
||||||
|
if setting == "on":
|
||||||
|
prof.settings_boolean_set("system", "newline", True)
|
||||||
|
prof.cons_show("syscmd.py newline enabled.")
|
||||||
|
return
|
||||||
|
|
||||||
|
if setting == "off":
|
||||||
|
prof.settings_boolean_set("system", "newline", False)
|
||||||
|
prof.cons_show("syscmd.py newline disabled.")
|
||||||
|
return
|
||||||
|
|
||||||
|
prof.cons_bad_cmd_usage("/paste")
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_system(arg1=None, arg2=None):
|
||||||
|
if not arg1:
|
||||||
|
create_win()
|
||||||
|
prof.win_focus(system_win)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if arg1 == "newline":
|
||||||
|
_handle_newline(arg2)
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "send":
|
||||||
|
_handle_send(arg2)
|
||||||
|
return
|
||||||
|
|
||||||
|
if arg1 == "exec":
|
||||||
|
_handle_exec(arg2)
|
||||||
|
return
|
||||||
|
|
||||||
|
prof.cons_bad_cmd_usage("/system")
|
||||||
|
|
||||||
|
|
||||||
|
def prof_init(version, status, account_name, fulljid):
|
||||||
|
synopsis = [
|
||||||
|
"/system",
|
||||||
|
"/system newline on|off",
|
||||||
|
"/system exec <comman>",
|
||||||
|
"/system send <command>"
|
||||||
|
]
|
||||||
|
description = "Run a system command, calling with no arguments will open or focus the system window."
|
||||||
|
args = [
|
||||||
|
[ "newline on|off", "Send newline before multiline command output, defaults to on" ],
|
||||||
|
[ "exec <command>", "Execute a command" ],
|
||||||
|
[ "send <command>", "Send the result of the command to the current recipient or room" ]
|
||||||
|
]
|
||||||
|
examples = [
|
||||||
|
"/system exec ls -l",
|
||||||
|
"/system send uname -a"
|
||||||
|
]
|
||||||
|
prof.register_command("/system", 0, 2, synopsis, description, args, examples, _cmd_system)
|
||||||
|
prof.completer_add("/system", [ "exec", "send", "newline" ])
|
||||||
|
prof.completer_add("/system newline", [ "on", "off" ])
|
||||||
@@ -78,8 +78,8 @@ def _search(search_terms):
|
|||||||
if len(results) > 0:
|
if len(results) > 0:
|
||||||
prof.win_show_themed(win, "wikipedia", "search", None, "Search results for \"" + search_terms + "\":")
|
prof.win_show_themed(win, "wikipedia", "search", None, "Search results for \"" + search_terms + "\":")
|
||||||
for index, result in enumerate(results):
|
for index, result in enumerate(results):
|
||||||
page_ac.append(result.encode("utf-8"))
|
page_ac.append(result)
|
||||||
prof.win_show_themed(win, "wikipedia", "search.results", None, result.encode("utf-8"))
|
prof.win_show_themed(win, "wikipedia", "search.results", None, result)
|
||||||
_update_autocomplete()
|
_update_autocomplete()
|
||||||
else:
|
else:
|
||||||
prof.win_show_themed(win, "wikipedia", "search.noresults", None, "No search results found for \"" + search_terms + "\"")
|
prof.win_show_themed(win, "wikipedia", "search.noresults", None, "No search results found for \"" + search_terms + "\"")
|
||||||
@@ -98,14 +98,14 @@ def _summary(page_str):
|
|||||||
prof.win_focus(win)
|
prof.win_focus(win)
|
||||||
return
|
return
|
||||||
|
|
||||||
link_ac.append(page.url.encode("utf-8"))
|
link_ac.append(page.url)
|
||||||
prof.completer_add("/wikipedia open", link_ac)
|
prof.completer_add("/wikipedia open", link_ac)
|
||||||
|
|
||||||
prof.win_show_themed(win, "wikipedia", "summary.title", None, page.title.encode("utf-8"))
|
prof.win_show_themed(win, "wikipedia", "summary.title", None, page.title)
|
||||||
prof.win_show_themed(win, "wikipedia", "summary.url", None, page.url.encode("utf-8"))
|
prof.win_show_themed(win, "wikipedia", "summary.url", None, page.url)
|
||||||
|
|
||||||
summary = wikipedia.summary(page_str)
|
summary = wikipedia.summary(page_str)
|
||||||
prof.win_show_themed(win, "wikipedia", "summary.text", None, summary.encode("utf-8"))
|
prof.win_show_themed(win, "wikipedia", "summary.text", None, summary)
|
||||||
prof.win_show(win, "")
|
prof.win_show(win, "")
|
||||||
prof.win_focus(win)
|
prof.win_focus(win)
|
||||||
|
|
||||||
@@ -119,8 +119,8 @@ def _page(page_str):
|
|||||||
prof.win_focus(win)
|
prof.win_focus(win)
|
||||||
return
|
return
|
||||||
|
|
||||||
prof.win_show_themed(win, "wikipedia", "page.title", None, page.title.encode("utf-8"))
|
prof.win_show_themed(win, "wikipedia", "page.title", None, page.title)
|
||||||
prof.win_show_themed(win, "wikipedia", "page.text", None, page.content.encode("utf-8"))
|
prof.win_show_themed(win, "wikipedia", "page.text", None, page.content)
|
||||||
prof.win_show(win, "")
|
prof.win_show(win, "")
|
||||||
prof.win_focus(win)
|
prof.win_focus(win)
|
||||||
|
|
||||||
@@ -138,8 +138,8 @@ def _images(page_str):
|
|||||||
|
|
||||||
prof.win_show_themed(win, "wikipedia", "images", None, "Images for " + page_str)
|
prof.win_show_themed(win, "wikipedia", "images", None, "Images for " + page_str)
|
||||||
for image in page.images:
|
for image in page.images:
|
||||||
prof.win_show_themed(win, "wikipedia", "images.url", None, image.encode("utf-8"))
|
prof.win_show_themed(win, "wikipedia", "images.url", None, image)
|
||||||
link_ac.append(image.encode("utf-8"))
|
link_ac.append(image)
|
||||||
prof.completer_add("/wikipedia open", link_ac)
|
prof.completer_add("/wikipedia open", link_ac)
|
||||||
prof.win_show(win, "")
|
prof.win_show(win, "")
|
||||||
prof.win_focus(win)
|
prof.win_focus(win)
|
||||||
@@ -159,8 +159,8 @@ def _links(page_str):
|
|||||||
prof.win_show_themed(win, "wikipedia", "links", None, "Links for " + page_str)
|
prof.win_show_themed(win, "wikipedia", "links", None, "Links for " + page_str)
|
||||||
|
|
||||||
for link in page.links:
|
for link in page.links:
|
||||||
prof.win_show_themed(win, "wikipedia", "links.link", None, link.encode("utf-8"))
|
prof.win_show_themed(win, "wikipedia", "links.link", None, link)
|
||||||
page_ac.append(link.encode("utf-8"))
|
page_ac.append(link)
|
||||||
_update_autocomplete()
|
_update_autocomplete()
|
||||||
prof.win_show(win, "")
|
prof.win_show(win, "")
|
||||||
prof.win_focus(win)
|
prof.win_focus(win)
|
||||||
@@ -179,8 +179,8 @@ def _refs(page_str):
|
|||||||
|
|
||||||
prof.win_show_themed(win, "wikipedia", "refs", None, "References for " + page_str)
|
prof.win_show_themed(win, "wikipedia", "refs", None, "References for " + page_str)
|
||||||
for ref in page.references:
|
for ref in page.references:
|
||||||
prof.win_show_themed(win, "wikipedia", "refs.url", None, ref.encode("utf-8"))
|
prof.win_show_themed(win, "wikipedia", "refs.url", None, ref)
|
||||||
link_ac.append(ref.encode("utf-8"))
|
link_ac.append(ref)
|
||||||
prof.completer_add("/wikipedia open", link_ac)
|
prof.completer_add("/wikipedia open", link_ac)
|
||||||
prof.win_show(win, "")
|
prof.win_show(win, "")
|
||||||
prof.win_focus(win)
|
prof.win_focus(win)
|
||||||
79
syscmd.py
79
syscmd.py
@@ -1,79 +0,0 @@
|
|||||||
"""
|
|
||||||
Allow running system commands in a plugin window, or send result to recipient
|
|
||||||
|
|
||||||
Theme options in ~/.local/share/profanity/plugin_themes
|
|
||||||
|
|
||||||
[system]
|
|
||||||
command=magenta
|
|
||||||
result=green
|
|
||||||
"""
|
|
||||||
|
|
||||||
import prof
|
|
||||||
import subprocess
|
|
||||||
|
|
||||||
system_win = "System"
|
|
||||||
|
|
||||||
|
|
||||||
def _get_result(command):
|
|
||||||
return subprocess.Popen(command, shell=True, stdout=subprocess.PIPE).stdout.read()
|
|
||||||
|
|
||||||
|
|
||||||
def _handle_win_input(win, command):
|
|
||||||
prof.win_show_themed(win, "system", "command", None, command)
|
|
||||||
prof.win_show(win, "")
|
|
||||||
result = _get_result(command)
|
|
||||||
split = result.splitlines()
|
|
||||||
for s in split:
|
|
||||||
prof.win_show_themed(win, "system", "result", None, s)
|
|
||||||
prof.win_show(win, "")
|
|
||||||
|
|
||||||
|
|
||||||
def create_win():
|
|
||||||
if prof.win_exists(system_win) == False:
|
|
||||||
prof.win_create(system_win, _handle_win_input)
|
|
||||||
|
|
||||||
|
|
||||||
def _cmd_system(arg1=None, arg2=None):
|
|
||||||
if not arg1:
|
|
||||||
create_win()
|
|
||||||
prof.win_focus(system_win)
|
|
||||||
elif arg1 == "send":
|
|
||||||
if arg2 == None:
|
|
||||||
prof.cons_bad_cmd_usage("/system")
|
|
||||||
else:
|
|
||||||
room = prof.get_current_muc()
|
|
||||||
recipient = prof.get_current_recipient()
|
|
||||||
if room == None and recipient == None:
|
|
||||||
prof.cons_show("You must be in a chat or muc window to send a system command")
|
|
||||||
prof.cons_alert()
|
|
||||||
else:
|
|
||||||
result = _get_result(arg2)
|
|
||||||
prof.send_line(u'\u000A' + result)
|
|
||||||
elif arg1 == "exec":
|
|
||||||
if arg2 == None:
|
|
||||||
prof.cons_bad_cmd_usage("/system")
|
|
||||||
else:
|
|
||||||
create_win()
|
|
||||||
prof.win_focus(system_win)
|
|
||||||
_handle_win_input(system_win, arg2)
|
|
||||||
else:
|
|
||||||
prof.cons_bad_cmd_usage("/system")
|
|
||||||
|
|
||||||
|
|
||||||
def prof_init(version, status, account_name, fulljid):
|
|
||||||
synopsis = [
|
|
||||||
"/system",
|
|
||||||
"/system exec <comman>",
|
|
||||||
"/system send <command>"
|
|
||||||
]
|
|
||||||
description = "Run a system command, calling with no arguments will open or focus the system window."
|
|
||||||
args = [
|
|
||||||
[ "exec <command>", "Execute a command" ],
|
|
||||||
[ "send <command>", "Send the result of the command to the current recipient or room" ]
|
|
||||||
]
|
|
||||||
examples = [
|
|
||||||
"/system exec ls -l",
|
|
||||||
"/system send uname -a"
|
|
||||||
]
|
|
||||||
prof.register_command("/system", 0, 2, synopsis, description, args, examples, _cmd_system)
|
|
||||||
prof.completer_add("/system", [ "exec", "send" ])
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
module RubyTest
|
|
||||||
|
|
||||||
def self.prof_init(version, status)
|
|
||||||
Prof::cons_show("RubyTest: init, " + version + ", " + status)
|
|
||||||
Prof::register_command("/ruby", 0, 1, "/ruby [arg]", "RubyTest", "RubyTest", cmd_ruby)
|
|
||||||
Prof::register_command("/rb_upper", 1, 1, "/rb_upper string", "RubyTest", "RubyTest", cmd_upper)
|
|
||||||
Prof::register_command("/rb_notify", 0, 0, "/rb_notify", "RubyTest", "RubyTest", cmd_notify)
|
|
||||||
Prof::register_command("/rb_vercheck", 0, 0, "/rb_vercheck", "RubyTest", "RubyTest", cmd_vercheck)
|
|
||||||
Prof::register_ac("/rb_complete", [ "aaaa", "bbbb", "bcbcbc" ])
|
|
||||||
Prof::register_ac("/rb_complete aaaa", [ "one", "two", "three", "four" ])
|
|
||||||
Prof::register_ac("/rb_complete bcbcbc", [ "james", "jim", "jane", "bob" ])
|
|
||||||
Prof::register_command("/rb_complete", 0, 2, "/rb_complete [arg1] [arg2]", "RubyTest", "RubyTest", cmd_ac)
|
|
||||||
Prof::register_timed(timer_test, 30)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_on_start
|
|
||||||
Prof::cons_show("RubyTest: prof_on_start")
|
|
||||||
Prof::log_debug("RubyTest: logged debug");
|
|
||||||
Prof::log_info("RubyTest: logged info");
|
|
||||||
Prof::log_warning("RubyTest: logged warning");
|
|
||||||
Prof::log_error("RubyTest: logged error");
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_on_shutdown
|
|
||||||
Prof::log_info("RubyTest: prof_on_shutdown");
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_on_connect(account_name, fulljid)
|
|
||||||
Prof::cons_show("RubyTest: prof_on_connect, " + account_name + ", " + fulljid)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_on_disconnect(account_name, fulljid)
|
|
||||||
Prof::cons_show("RubyTest: prof_on_disconnect, " + account_name + ", " + fulljid)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_pre_chat_message_display(jid, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_pre_chat_message_display, " + jid + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
return message + "[RB_pre_chat_message_display]"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_post_chat_message_display(jid, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_post_chat_message_display, " + jid + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_pre_chat_message_send(jid, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_pre_chat_message_send, " + jid + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
return message + "[RB_pre_chat_message_send]"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_post_chat_message_send(jid, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_post_chat_message_send, " + jid + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_pre_room_message_display(room, nick, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_pre_room_message_display, " + room + ", " + nick + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
return message + "[RB_pre_room_message_display]"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_post_room_message_display(room, nick, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_post_room_message_display, " + room + ", " + nick + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_pre_room_message_send(room, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_pre_room_message_send, " + room + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
return message + "[RB_pre_room_message_send]"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_post_room_message_send(room, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_post_room_message_send, " + room + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_pre_priv_message_display(room, nick, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_pre_priv_message_display, " + room + ", " + nick + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
return message + "[RB_pre_priv_message_display]"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_post_priv_message_display(room, nick, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_post_priv_message_display, " + room + ", " + nick + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_pre_priv_message_send(room, nick, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_pre_priv_message_send, " + room + ", " + nick + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
return message + "[RB_pre_priv_message_send]"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_post_priv_message_send(room, nick, message)
|
|
||||||
Prof::cons_show("RubyTest: prof_post_priv_message_send, " + room + ", " + nick + ", " + message)
|
|
||||||
Prof::cons_alert
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.cmd_ruby
|
|
||||||
return Proc.new { | msg |
|
|
||||||
if msg
|
|
||||||
Prof::cons_show("RubyTest: /ruby command called, arg = " + msg)
|
|
||||||
else
|
|
||||||
Prof::cons_show("RubyTest: /ruby command called with no arg")
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.cmd_ac
|
|
||||||
return Proc.new { | arg1, arg2 |
|
|
||||||
Prof::cons_show("RubyTest: /rb_complete called")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.cmd_notify
|
|
||||||
return Proc.new {
|
|
||||||
Prof::notify("RubyTest: notify", 2000, "Plugins")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.cmd_vercheck
|
|
||||||
return Proc.new {
|
|
||||||
Prof::send_line("/vercheck")
|
|
||||||
Prof::cons_show("RubyTest: sent \"/vercheck\" command")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.timer_test
|
|
||||||
return Proc.new {
|
|
||||||
Prof::cons_show("RubyTest: timer fired.")
|
|
||||||
Prof::cons_alert
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.cmd_upper
|
|
||||||
return Proc.new { | line |
|
|
||||||
win_tag = "Ruby Plygin"
|
|
||||||
if (Prof::win_exists(win_tag) == false)
|
|
||||||
Prof::win_create(win_tag, handle_upper)
|
|
||||||
end
|
|
||||||
Prof::win_focus(win_tag)
|
|
||||||
if (line)
|
|
||||||
handle_upper.call(win_tag, line)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.handle_upper
|
|
||||||
return Proc.new { | win, line |
|
|
||||||
upper = line.upcase
|
|
||||||
Prof::win_show(win, upper)
|
|
||||||
Prof::win_show_red(win, upper + " red")
|
|
||||||
Prof::win_show_yellow(win, upper + " yellow")
|
|
||||||
Prof::win_show_green(win, upper + " green")
|
|
||||||
Prof::win_show_cyan(win, upper + " cyan")
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
module RubyThread
|
|
||||||
@counter = 0
|
|
||||||
|
|
||||||
def self.inc_counter()
|
|
||||||
while true
|
|
||||||
sleep(1)
|
|
||||||
@counter = @counter + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.cmd_rcount()
|
|
||||||
return Proc.new {
|
|
||||||
instance_eval {
|
|
||||||
Prof::cons_show("RCounter: " + @counter)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prof_init(version, status)
|
|
||||||
Thread.new { self.inc_counter() }
|
|
||||||
Prof::register_command("/rcount", 0, 0, "/rcount", "Ruby threaded example", "Ruby threaded example", cmd_rcount)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,116 +0,0 @@
|
|||||||
local luatest = {}
|
|
||||||
|
|
||||||
local function cmd_lua(msg)
|
|
||||||
if msg then
|
|
||||||
prof_cons_show("luatest: /lua command called, arg = " .. msg)
|
|
||||||
else
|
|
||||||
prof_cons_show("luatest: /lua command called with no arg")
|
|
||||||
end
|
|
||||||
prof_cons_alert()
|
|
||||||
prof_notify("luatest: notify", 8000, "Plugins")
|
|
||||||
prof_send_line("/account list")
|
|
||||||
prof_cons_show("luatest: sent \"/account list\" command")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function timer_test()
|
|
||||||
prof_cons_show("luatest: timer fired.")
|
|
||||||
recipient = prof_get_current_recipient()
|
|
||||||
if recipient then
|
|
||||||
prof_cons_show(" current recipient = " .. recipient)
|
|
||||||
end
|
|
||||||
prof_cons_alert()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function handle_bracket(win, line)
|
|
||||||
prof_win_show(win, "(" .. line .. ")")
|
|
||||||
prof_win_show_red(win, "Red")
|
|
||||||
prof_win_show_yellow(win, "Yellow")
|
|
||||||
prof_win_show_green(win, "Green")
|
|
||||||
prof_win_show_cyan(win, "Cyan")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function cmd_bracket(line)
|
|
||||||
win_tag = "Parenthesise echo";
|
|
||||||
if prof_win_exists(win_tag) == false then
|
|
||||||
prof_win_create(win_tag, handle_bracket);
|
|
||||||
end
|
|
||||||
|
|
||||||
prof_win_focus(win_tag);
|
|
||||||
|
|
||||||
if line then
|
|
||||||
handle_bracket(win_tag, line)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_init(version, status)
|
|
||||||
prof_cons_show("luatest: init, " .. version .. ", " .. status)
|
|
||||||
|
|
||||||
prof_register_command("/lua", 0, 1, "/lua", "luatest", "luatest", cmd_lua)
|
|
||||||
prof_register_command("/bracket", 0, 1, "/bracket", "Parenthesise input string", "Parenthesise input string", cmd_bracket);
|
|
||||||
|
|
||||||
prof_register_ac("/lcomplete", { "football", "footy", "tennis" })
|
|
||||||
prof_register_ac("/lcomplete football", { "goal", "out", "try", "given" })
|
|
||||||
prof_register_ac("/lcomplete tennis", { "test", "prod", "dev", "stage" })
|
|
||||||
prof_register_command("/lcomplete", 0, 2, "/lcomplete", "Lua completion", "Lua completion", cmd_bracket)
|
|
||||||
|
|
||||||
prof_register_timed(timer_test, 10)
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_start()
|
|
||||||
prof_cons_show("luatest: on_start")
|
|
||||||
prof_log_debug("luatest: logged debug");
|
|
||||||
prof_log_info("luatest: logged info");
|
|
||||||
prof_log_warning("luatest: logged warning");
|
|
||||||
prof_log_error("luatest: logged error");
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_connect(account_name, fulljid)
|
|
||||||
prof_cons_show("luatest: on_connect, " .. account_name .. ", " .. fulljid)
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_disconnect(account_name, fulljid)
|
|
||||||
prof_cons_show("luatest: on_disconnect, " .. account_name .. ", " .. fulljid)
|
|
||||||
prof_log_info("luatest: on_disconnect, " .. account_name .. ", " .. fulljid)
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_message_received(jid, message)
|
|
||||||
prof_cons_show("luatest: on_message_received, " .. jid .. ", " .. message)
|
|
||||||
prof_cons_alert()
|
|
||||||
return message .. "[LUA]"
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_room_message_received(room, nick, message)
|
|
||||||
prof_cons_show("luatest: on_room_message_received, " .. room .. ", " .. nick .. ", " .. message)
|
|
||||||
prof_cons_alert()
|
|
||||||
return message .. "[LUA]"
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_private_message_received(room, nick, message)
|
|
||||||
prof_cons_show("luatest: on_private_message_received, " .. room .. ", " .. nick .. ", " .. message)
|
|
||||||
prof_cons_alert()
|
|
||||||
return message .. "[LUA]"
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_message_send(jid, message)
|
|
||||||
prof_cons_show("luatest: on_message_send, " .. jid .. ", " .. message)
|
|
||||||
prof_cons_alert()
|
|
||||||
return message .. "[LUA]"
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_private_message_send(room, nick, message)
|
|
||||||
prof_cons_show("luatest: on_private_message_send, " .. room .. ", " .. nick .. ", " .. message)
|
|
||||||
prof_cons_alert()
|
|
||||||
return message .. "[LUA]"
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_room_message_send(room, message)
|
|
||||||
prof_cons_show("luatest: on_room_message_send, " .. room .. ", " .. message)
|
|
||||||
prof_cons_alert()
|
|
||||||
return message .. "[LUA]"
|
|
||||||
end
|
|
||||||
|
|
||||||
function luatest.prof_on_shutdown()
|
|
||||||
prof_log_info("luatest: on_shutdown")
|
|
||||||
end
|
|
||||||
|
|
||||||
return luatest
|
|
||||||
@@ -1,558 +0,0 @@
|
|||||||
import prof
|
|
||||||
|
|
||||||
import threading
|
|
||||||
import time
|
|
||||||
|
|
||||||
plugin_win = "Python Test"
|
|
||||||
|
|
||||||
count = 0
|
|
||||||
ping_id = 1
|
|
||||||
|
|
||||||
def _inc_counter():
|
|
||||||
global count
|
|
||||||
while True:
|
|
||||||
time.sleep(5)
|
|
||||||
count = count + 1
|
|
||||||
|
|
||||||
def _handle_win_input(win, line):
|
|
||||||
prof.win_show(win, "Input received: " + line)
|
|
||||||
|
|
||||||
def _create_win():
|
|
||||||
if prof.win_exists(plugin_win) == False:
|
|
||||||
prof.win_create(plugin_win, _handle_win_input)
|
|
||||||
|
|
||||||
def _consalert():
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.cons_alert()
|
|
||||||
prof.win_show(plugin_win, "called -> prof.cons_alert")
|
|
||||||
|
|
||||||
def _consshow(msg):
|
|
||||||
if not msg:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.cons_show(msg)
|
|
||||||
prof.win_show(plugin_win, "called -> prof.cons_show: " + msg)
|
|
||||||
|
|
||||||
def _consshow_t(group, key, dflt, msg):
|
|
||||||
if not group or not key or not dflt or not msg:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
groupval = None if group == "none" else group
|
|
||||||
keyval = None if key == "none" else key
|
|
||||||
dfltval = None if dflt == "none" else dflt
|
|
||||||
prof.cons_show_themed(groupval, keyval, dfltval, msg)
|
|
||||||
prof.win_show(plugin_win, "called -> prof.cons_show_themed: " + group + ", " + key + ", " + dflt + ", " + msg)
|
|
||||||
|
|
||||||
def _constest():
|
|
||||||
res = prof.current_win_is_console()
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
if res:
|
|
||||||
prof.win_show(plugin_win, "called -> prof.current_win_is_console: true")
|
|
||||||
else:
|
|
||||||
prof.win_show(plugin_win, "called -> prof.current_win_is_console: false")
|
|
||||||
|
|
||||||
def _winshow(msg):
|
|
||||||
if not msg:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, msg)
|
|
||||||
prof.win_show(plugin_win, "called -> prof.win_show: " + msg)
|
|
||||||
|
|
||||||
def _winshow_t(group, key, dflt, msg):
|
|
||||||
if not group or not key or not dflt or not msg:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
groupval = None if group == "none" else group
|
|
||||||
keyval = None if key == "none" else key
|
|
||||||
dfltval = None if dflt == "none" else dflt
|
|
||||||
prof.win_show_themed(plugin_win, groupval, keyval, dfltval, msg)
|
|
||||||
prof.win_show(plugin_win, "called -> prof_win_show_themed: " + group + ", " + key + ", " + dflt + ", " + msg)
|
|
||||||
|
|
||||||
def _sendline(line):
|
|
||||||
if not line:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.send_line(line)
|
|
||||||
prof.win_show(plugin_win, "called -> prof.send_line: " + line)
|
|
||||||
|
|
||||||
def _notify(msg):
|
|
||||||
if not msg:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.notify(msg, 5000, "python-test plugin")
|
|
||||||
prof.win_show(plugin_win, "called -> prof.notify: " + msg)
|
|
||||||
|
|
||||||
def _get(subject):
|
|
||||||
if subject == "recipient":
|
|
||||||
_create_win()
|
|
||||||
recipient = prof.get_current_recipient();
|
|
||||||
if recipient:
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, "called -> prof.get_current_recipient: " + recipient)
|
|
||||||
else:
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, "called -> prof_get_current_recipient: <none>")
|
|
||||||
elif subject == "room":
|
|
||||||
_create_win()
|
|
||||||
room = prof.get_current_muc()
|
|
||||||
if room:
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, "called -> prof_get_current_muc: " + room)
|
|
||||||
else:
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, "called -> prof_get_current_muc: <none>")
|
|
||||||
elif subject == "nick":
|
|
||||||
_create_win()
|
|
||||||
nick = prof.get_current_nick()
|
|
||||||
if nick:
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, "called -> prof_get_current_nick: " + nick)
|
|
||||||
else:
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, "called -> prof_get_current_nick: <none>")
|
|
||||||
elif subject == "occupants":
|
|
||||||
_create_win()
|
|
||||||
occupants = prof.get_current_occupants()
|
|
||||||
if occupants:
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, "called -> prof_get_current_occupants:")
|
|
||||||
for occupant in occupants:
|
|
||||||
prof.win_show(plugin_win, occupant)
|
|
||||||
else:
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, "called -> prof_get_current_occupants: <none>")
|
|
||||||
else:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
|
|
||||||
def _log(level, msg):
|
|
||||||
if not level or not msg:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if level == "debug":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.log_debug(msg)
|
|
||||||
prof.win_show(plugin_win, "called -> prof.log_debug: " + msg)
|
|
||||||
elif level == "info":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.log_info(msg)
|
|
||||||
prof.win_show(plugin_win, "called -> prof.log_info: " + msg)
|
|
||||||
elif level == "warning":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.log_warning(msg)
|
|
||||||
prof.win_show(plugin_win, "called -> prof.log_warning: " + msg)
|
|
||||||
elif level == "error":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.log_error(msg)
|
|
||||||
prof.win_show(plugin_win, "called -> prof.log_error: " + msg)
|
|
||||||
else:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
|
|
||||||
def _count():
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.win_show(plugin_win, "Count: " + str(count))
|
|
||||||
|
|
||||||
def _ping(jid):
|
|
||||||
global ping_id
|
|
||||||
|
|
||||||
if not jid:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
res = prof.send_stanza("<iq to='" + jid + "' id='pythonplugin-" + str(ping_id) + "' type='get'><ping xmlns='urn:xmpp:ping'/></iq>")
|
|
||||||
ping_id = ping_id + 1
|
|
||||||
if res:
|
|
||||||
prof.win_show(plugin_win, "Ping sent successfully")
|
|
||||||
else:
|
|
||||||
prof.win_show(plugin_win, "Error sending ping")
|
|
||||||
|
|
||||||
def _boolean(op, group, key, value_str):
|
|
||||||
if op != "get" and op != "set":
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if group == None or key == None:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if op == "set" and value_str != "true" and value_str != "false":
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if op == "get":
|
|
||||||
dflt = False
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
res = prof.settings_get_boolean(group, key, dflt)
|
|
||||||
if res:
|
|
||||||
prof.win_show(plugin_win, "Boolean setting: TRUE")
|
|
||||||
else:
|
|
||||||
prof.win_show(plugin_win, "Boolean setting: FALSE")
|
|
||||||
elif op == "set":
|
|
||||||
value = False
|
|
||||||
if value_str == "true":
|
|
||||||
value = True
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.settings_set_boolean(group, key, value)
|
|
||||||
prof.win_show(plugin_win, "Set [" + group + "] " + key + " to " + str(value))
|
|
||||||
|
|
||||||
def _string(op, group, key, value):
|
|
||||||
if op != "get" and op != "set":
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if group == None or key == None:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if op == "set" and not value:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if op == "get":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
res = prof.settings_get_string(group, key, None)
|
|
||||||
if res:
|
|
||||||
prof.win_show(plugin_win, "String setting: " + res)
|
|
||||||
else:
|
|
||||||
prof.win_show(plugin_win, "String setting: None")
|
|
||||||
elif op == "set":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.settings_set_string(group, key, value)
|
|
||||||
prof.win_show(plugin_win, "Set [" + group + "] " + key + " to " + value)
|
|
||||||
|
|
||||||
def _int(op, group, key, value):
|
|
||||||
if op != "get" and op != "set":
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if group == None or key == None:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if op == "get":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
res = prof.settings_get_int(group, key, 0)
|
|
||||||
prof.win_show(plugin_win, "Integer setting: " + str(res))
|
|
||||||
elif op == "set":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.settings_set_int(group, key, int(value))
|
|
||||||
prof.win_show(plugin_win, "Set [" + group + "] " + key + " to " + str(value))
|
|
||||||
|
|
||||||
def _incoming(barejid, resource, message):
|
|
||||||
if not barejid or not resource or not message:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
prof.incoming_message(barejid, resource, message)
|
|
||||||
|
|
||||||
def _completer(op, item):
|
|
||||||
if not item:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
return
|
|
||||||
|
|
||||||
if op == "add":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.completer_add("/python-test", [item])
|
|
||||||
prof.win_show(plugin_win, "Added \"" + item + "\" to /python-test completer")
|
|
||||||
prof.completer_add("/python-test completer remove", [item])
|
|
||||||
elif op == "remove":
|
|
||||||
_create_win()
|
|
||||||
prof.win_focus(plugin_win)
|
|
||||||
prof.completer_remove("/python-test", [item])
|
|
||||||
prof.win_show(plugin_win, "Removed \"" + item + "\" to /python-test completer")
|
|
||||||
prof.completer_remove("/python-test completer remove", [item])
|
|
||||||
else:
|
|
||||||
prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
|
|
||||||
|
|
||||||
def _cmd_pythontest(subcmd=None, arg1=None, arg2=None, arg3=None, arg4=None):
|
|
||||||
if subcmd == "consalert": _consalert()
|
|
||||||
elif subcmd == "consshow": _consshow(arg1)
|
|
||||||
elif subcmd == "consshow_t": _consshow_t(arg1, arg2, arg3, arg4)
|
|
||||||
elif subcmd == "constest": _constest()
|
|
||||||
elif subcmd == "winshow": _winshow(arg1)
|
|
||||||
elif subcmd == "winshow_t": _winshow_t(arg1, arg2, arg3, arg4)
|
|
||||||
elif subcmd == "sendline": _sendline(arg1)
|
|
||||||
elif subcmd == "notify": _notify(arg1)
|
|
||||||
elif subcmd == "get": _get(arg1)
|
|
||||||
elif subcmd == "log": _log(arg1, arg2)
|
|
||||||
elif subcmd == "count": _count()
|
|
||||||
elif subcmd == "ping": _ping(arg1)
|
|
||||||
elif subcmd == "boolean": _boolean(arg1, arg2, arg3, arg4)
|
|
||||||
elif subcmd == "string": _string(arg1, arg2, arg3, arg4)
|
|
||||||
elif subcmd == "int": _int(arg1, arg2, arg3, arg4)
|
|
||||||
elif subcmd == "incoming": _incoming(arg1, arg2, arg3)
|
|
||||||
elif subcmd == "completer": _completer(arg1, arg2)
|
|
||||||
else: prof.cons_bad_cmd_usage("/python-test")
|
|
||||||
|
|
||||||
def timed_callback():
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "timed -> timed_callback called")
|
|
||||||
|
|
||||||
def prof_init(version, status, account_name, fulljid):
|
|
||||||
t = threading.Thread(target=_inc_counter)
|
|
||||||
t.daemon = True
|
|
||||||
t.start()
|
|
||||||
|
|
||||||
prof.disco_add_feature("urn:xmpp:profanity:python_test_plugin");
|
|
||||||
|
|
||||||
prof.win_create(plugin_win, _handle_win_input)
|
|
||||||
if account_name and fulljid:
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_init: " + version + ", " + status + ", " + account_name + ", " + fulljid)
|
|
||||||
else:
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_init: " + version + ", " + status)
|
|
||||||
|
|
||||||
synopsis = [
|
|
||||||
"/python-test consalert",
|
|
||||||
"/python-test consshow <message>",
|
|
||||||
"/python-test consshow_t <group> <key> <default> <message>",
|
|
||||||
"/python-test constest",
|
|
||||||
"/python-test winshow <message>",
|
|
||||||
"/python-test winshow_t <group> <key> <default> <message>",
|
|
||||||
"/python-test notify <message>",
|
|
||||||
"/python-test sendline <line>",
|
|
||||||
"/python-test get recipient|room|nick|occupants",
|
|
||||||
"/python-test log debug|info|warning|error <message>",
|
|
||||||
"/python-test count",
|
|
||||||
"/python-test ping <jid>",
|
|
||||||
"/python-test boolean get <group> <key>",
|
|
||||||
"/python-test boolean set <group> <key> <value>",
|
|
||||||
"/python-test string get <group> <key>",
|
|
||||||
"/python-test string set <group> <key> <value>",
|
|
||||||
"/python-test int get <group> <key>",
|
|
||||||
"/python-test int set <group> <key> <value>",
|
|
||||||
"/python-test incoming <barejid> <resource> <message>",
|
|
||||||
"/python-test completer add|remove <item>"
|
|
||||||
]
|
|
||||||
description = "Python test plugins. All commands focus the plugin window."
|
|
||||||
args = [
|
|
||||||
[ "consalert", "Highlight the console window in the status bar" ],
|
|
||||||
[ "consshow <message>", "Show the message in the console window" ],
|
|
||||||
[ "consshow_t <group> <key> <default> <message>", "Show the themed message in the console window. " ],
|
|
||||||
[ "constest", "Show whether the command was run in the console." ],
|
|
||||||
[ "winshow <message>", "Show the message in the plugin window" ],
|
|
||||||
[ "winshow_t <group> <key> <default> <message>", "Show the themed message in the plugin window. " ],
|
|
||||||
[ "notify <message>", "Send a desktop notification with message" ],
|
|
||||||
[ "sendline <line>", "Pass line to profanity to process" ],
|
|
||||||
[ "get recipient", "Show the current chat recipient, if in a chat window" ],
|
|
||||||
[ "get room", "Show the current room JID, if ina a chat room"],
|
|
||||||
[ "get nick", "Show nickname in current room, if ina a chat room"],
|
|
||||||
[ "get occupants", "Show occupants in current room, if ina a chat room"],
|
|
||||||
[ "log debug|info|warning|error <message>", "Log a message at the specified level" ],
|
|
||||||
[ "count", "Show the counter, incremented every 5 seconds by a worker thread" ],
|
|
||||||
[ "ping <jid>", "Send an XMPP ping to the specified Jabber ID" ],
|
|
||||||
[ "boolean get <group> <key>", "Get a boolean setting" ],
|
|
||||||
[ "boolean set <group> <key> <value>", "Set a boolean setting" ],
|
|
||||||
[ "string get <group> <key>", "Get a string setting" ],
|
|
||||||
[ "string set <group> <key> <value>", "Set a string setting" ],
|
|
||||||
[ "int get <group> <key>", "Get a integer setting" ],
|
|
||||||
[ "int set <group> <key> <value>", "Set a integer setting" ],
|
|
||||||
[ "incoming <barejid> <resource> <message>", "Show an incoming message." ],
|
|
||||||
[ "completer add <item>", "Add an autocomplete item to the /c-test command." ],
|
|
||||||
[ "completer remove <item>", "Remove an autocomplete item from the /c-test command." ]
|
|
||||||
]
|
|
||||||
examples = [
|
|
||||||
"/python-test sendline /about",
|
|
||||||
"/python-test log debug \"Test debug message\"",
|
|
||||||
"/python-test consshow_t c-test cons.show none \"This is themed\"",
|
|
||||||
"/python-test consshow_t none none bold_cyan \"This is bold_cyan\"",
|
|
||||||
"/python-test ping buddy@server.org"
|
|
||||||
]
|
|
||||||
|
|
||||||
prof.register_command("/python-test", 1, 5, synopsis, description, args, examples, _cmd_pythontest)
|
|
||||||
|
|
||||||
prof.completer_add("/python-test",
|
|
||||||
[
|
|
||||||
"consalert",
|
|
||||||
"consshow",
|
|
||||||
"consshow_t",
|
|
||||||
"constest",
|
|
||||||
"winshow",
|
|
||||||
"winshow_t",
|
|
||||||
"notify",
|
|
||||||
"sendline",
|
|
||||||
"get",
|
|
||||||
"log",
|
|
||||||
"count",
|
|
||||||
"ping",
|
|
||||||
"boolean",
|
|
||||||
"string",
|
|
||||||
"int",
|
|
||||||
"incoming",
|
|
||||||
"completer"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
prof.completer_add("/python-test get",
|
|
||||||
[ "recipient", "room", "nick", "occupants" ]
|
|
||||||
)
|
|
||||||
prof.completer_add("/python-test log",
|
|
||||||
[ "debug", "info", "warning", "error" ]
|
|
||||||
)
|
|
||||||
prof.completer_add("/python-test boolean",
|
|
||||||
[ "get", "set" ]
|
|
||||||
)
|
|
||||||
prof.completer_add("/python-test string",
|
|
||||||
[ "get", "set" ]
|
|
||||||
)
|
|
||||||
prof.completer_add("/python-test int",
|
|
||||||
[ "get", "set" ]
|
|
||||||
)
|
|
||||||
prof.completer_add("/python-test completer",
|
|
||||||
[ "add", "remove" ]
|
|
||||||
)
|
|
||||||
|
|
||||||
prof.register_timed(timed_callback, 30)
|
|
||||||
|
|
||||||
def prof_on_start():
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_start")
|
|
||||||
|
|
||||||
def prof_on_shutdown():
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_shutdown")
|
|
||||||
|
|
||||||
def prof_on_connect(account_name, fulljid):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_connect: " + account_name + ", " + fulljid)
|
|
||||||
|
|
||||||
def prof_on_disconnect(account_name, fulljid):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_disconnect: " + account_name + ", " + fulljid)
|
|
||||||
|
|
||||||
def prof_pre_chat_message_display(jid, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_pre_chat_message_display: " + jid + ", " + message)
|
|
||||||
|
|
||||||
def prof_post_chat_message_display(jid, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_post_chat_message_display: " + jid + ", " + message)
|
|
||||||
|
|
||||||
def prof_pre_chat_message_send(jid, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_pre_chat_message_send: " + jid + ", " + message)
|
|
||||||
|
|
||||||
def prof_post_chat_message_send(jid, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_post_chat_message_send: " + jid + ", " + message)
|
|
||||||
|
|
||||||
def prof_pre_room_message_display(room, nick, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_pre_room_message_display: " + room + ", " + nick + ", " + message)
|
|
||||||
|
|
||||||
def prof_post_room_message_display(room, nick, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_post_room_message_display: " + room + ", " + nick + ", " + message)
|
|
||||||
|
|
||||||
def prof_pre_room_message_send(room, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_pre_room_message_send: " + room + ", " + message)
|
|
||||||
|
|
||||||
def prof_post_room_message_send(room, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_post_room_message_send: " + room + ", " + message)
|
|
||||||
|
|
||||||
def prof_on_room_history_message(room, nick, message, timestamp):
|
|
||||||
_create_win()
|
|
||||||
if timestamp:
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_room_history_message: " + room + ", " + nick + ", " + message + ", " + timestamp)
|
|
||||||
else:
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_room_history_message: " + room + ", " + nick + ", " + message)
|
|
||||||
|
|
||||||
def prof_pre_priv_message_display(room, nick, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_pre_priv_message_display: " + room + ", " + nick + ", " + message)
|
|
||||||
|
|
||||||
def prof_post_priv_message_display(room, nick, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_post_priv_message_display: " + room + ", " + nick + ", " + message)
|
|
||||||
|
|
||||||
def prof_pre_priv_message_send(room, nick, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_pre_priv_message_send: " + room + ", " + nick + ", " + message)
|
|
||||||
|
|
||||||
def prof_post_priv_message_send(room, nick, message):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_post_priv_message_send: " + room + ", " + nick + ", " + message)
|
|
||||||
|
|
||||||
def prof_on_message_stanza_send(stanza):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_message_stanza_send: " + stanza)
|
|
||||||
|
|
||||||
def prof_on_message_stanza_receive(stanza):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_message_stanza_receive: " + stanza)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def prof_on_presence_stanza_send(stanza):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_presence_stanza_send: " + stanza)
|
|
||||||
|
|
||||||
def prof_on_presence_stanza_receive(stanza):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_presence_stanza_receive: " + stanza)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def prof_on_iq_stanza_send(stanza):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_iq_stanza_send: " + stanza)
|
|
||||||
|
|
||||||
def prof_on_iq_stanza_receive(stanza):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_iq_stanza_receive: " + stanza)
|
|
||||||
return True
|
|
||||||
|
|
||||||
def prof_on_contact_offline(barejid, resource, status):
|
|
||||||
_create_win()
|
|
||||||
if status:
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_contact_offline: " + barejid + "/" + resource + " \"" + status + "\"")
|
|
||||||
else:
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_contact_offline: " + barejid + "/" + resource)
|
|
||||||
|
|
||||||
def prof_on_contact_presence(barejid, resource, presence, status, priority):
|
|
||||||
_create_win()
|
|
||||||
if status:
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_contact_presence: " + barejid + "/" + resource + " " + presence + " " + str(priority) + " \"" + status + "\"")
|
|
||||||
else:
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_contact_presence: " + barejid + "/" + resource + " " + presence + " " + str(priority))
|
|
||||||
|
|
||||||
def prof_on_chat_win_focus(barejid):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_chat_win_focus: " + barejid)
|
|
||||||
|
|
||||||
def prof_on_room_win_focus(roomjid):
|
|
||||||
_create_win()
|
|
||||||
prof.win_show(plugin_win, "fired -> prof_on_room_win_focus: " + roomjid)
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
UNAME_S := $(shell uname -s)
|
|
||||||
ifeq ($(UNAME_S),Darwin)
|
|
||||||
LINK_FLAGS := -fno-common -flat_namespace -bundle -undefined suppress
|
|
||||||
else
|
|
||||||
LINK_FLAGS := -shared -fpic
|
|
||||||
endif
|
|
||||||
|
|
||||||
all: test-c-plugin.so
|
|
||||||
|
|
||||||
%.so:%.o
|
|
||||||
$(CC) $(LINK_FLAGS) -lprofanity -o $@ $^
|
|
||||||
|
|
||||||
%.o:%.c
|
|
||||||
$(CC) $(INCLUDE) -D_GNU_SOURCE -D_BSD_SOURCE -fpic -g3 -O0 -std=c99 \
|
|
||||||
-pedantic -c -o $@ $<
|
|
||||||
|
|
||||||
clean:
|
|
||||||
$(RM) test-c-plugin.so
|
|
||||||
@@ -1,942 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include <profapi.h>
|
|
||||||
|
|
||||||
static PROF_WIN_TAG plugin_win = "C Test";
|
|
||||||
static pthread_t worker_thread;
|
|
||||||
static int count = 0;
|
|
||||||
static int ping_id = 1;
|
|
||||||
|
|
||||||
void*
|
|
||||||
inc_counter(void *arg)
|
|
||||||
{
|
|
||||||
while (1) {
|
|
||||||
sleep(5);
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
handle_win_input(PROF_WIN_TAG win, char *line)
|
|
||||||
{
|
|
||||||
char *str = "Input received: ";
|
|
||||||
char buf[strlen(str) + strlen(line) + 1];
|
|
||||||
sprintf(buf, "%s%s", str, line);
|
|
||||||
prof_win_show(win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
create_win(void)
|
|
||||||
{
|
|
||||||
if (!prof_win_exists(plugin_win)) {
|
|
||||||
prof_win_create(plugin_win, handle_win_input);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
consalert(void)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_cons_alert();
|
|
||||||
prof_win_show(plugin_win, "called -> prof_cons_alert");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
consshow(char *msg)
|
|
||||||
{
|
|
||||||
if (msg == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_cons_show(msg);
|
|
||||||
char *str = "called -> prof_cons_show: ";
|
|
||||||
char buf[strlen(str) + strlen(msg)];
|
|
||||||
sprintf(buf, "%s%s", str, msg);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
consshow_t(char *group, char *key, char *def, char *msg)
|
|
||||||
{
|
|
||||||
if (group == NULL || key == NULL || def == NULL || msg == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char *groupval = strcmp(group, "none") == 0 ? NULL : group;
|
|
||||||
char *keyval = strcmp(key, "none") == 0 ? NULL : key;
|
|
||||||
char *defval = strcmp(def, "none") == 0 ? NULL : def;
|
|
||||||
prof_cons_show_themed(groupval, keyval, defval, msg);
|
|
||||||
char *str = "called -> prof_cons_show_themed: ";
|
|
||||||
char buf[strlen(str) + strlen(group) + 2 + strlen(key) + 2 + strlen(def) + 2 + strlen(msg)];
|
|
||||||
sprintf(buf, "%s%s, %s, %s, %s", str, group, key, def, msg);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
constest(void)
|
|
||||||
{
|
|
||||||
int res = prof_current_win_is_console();
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
if (res) {
|
|
||||||
prof_win_show(plugin_win, "called -> prof_current_win_is_console: true");
|
|
||||||
} else {
|
|
||||||
prof_win_show(plugin_win, "called -> prof_current_win_is_console: false");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
winshow(char *msg)
|
|
||||||
{
|
|
||||||
if (msg == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_win_show(plugin_win, msg);
|
|
||||||
char *str = "called -> prof_win_show: ";
|
|
||||||
char buf[strlen(str) + strlen(msg)];
|
|
||||||
sprintf(buf, "%s%s", str, msg);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
winshow_t(char *group, char *key, char *def, char *msg)
|
|
||||||
{
|
|
||||||
if (group == NULL || key == NULL || def == NULL || msg == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char *groupval = strcmp(group, "none") == 0 ? NULL : group;
|
|
||||||
char *keyval = strcmp(key, "none") == 0 ? NULL : key;
|
|
||||||
char *defval = strcmp(def, "none") == 0 ? NULL : def;
|
|
||||||
prof_win_show_themed(plugin_win, groupval, keyval, defval, msg);
|
|
||||||
char *str = "called -> prof_win_show_themed: ";
|
|
||||||
char buf[strlen(str) + strlen(group) + 2 + strlen(key) + 2 + strlen(def) + 2 + strlen(msg)];
|
|
||||||
sprintf(buf, "%s%s, %s, %s, %s", str, group, key, def, msg);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
sendline(char *line)
|
|
||||||
{
|
|
||||||
if (line == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_send_line(line);
|
|
||||||
char *str = "called -> prof_send_line: ";
|
|
||||||
char buf[strlen(str) + strlen(line)];
|
|
||||||
sprintf(buf, "%s%s", str, line);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
donotify(char *msg)
|
|
||||||
{
|
|
||||||
if (msg == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_notify(msg, 5000, "c-test plugin");
|
|
||||||
char *str = "called -> prof_notify: ";
|
|
||||||
char buf[strlen(str) + strlen(msg)];
|
|
||||||
sprintf(buf, "%s%s", str, msg);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
getsubject(char *subject)
|
|
||||||
{
|
|
||||||
if (subject == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(subject, "recipient") == 0) {
|
|
||||||
create_win();
|
|
||||||
char *recipient = prof_get_current_recipient();
|
|
||||||
if (recipient) {
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char *str = "called -> prof_get_current_recipient: ";
|
|
||||||
char buf[strlen(str) + strlen(recipient)];
|
|
||||||
sprintf(buf, "%s%s", str, recipient);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else {
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_win_show(plugin_win, "called -> prof_get_current_recipient: <none>");
|
|
||||||
}
|
|
||||||
} else if (strcmp(subject, "room") == 0) {
|
|
||||||
create_win();
|
|
||||||
char *room = prof_get_current_muc();
|
|
||||||
if (room) {
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char *str = "called -> prof_get_current_muc: ";
|
|
||||||
char buf[strlen(str) + strlen(room)];
|
|
||||||
sprintf(buf, "%s%s", str, room);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else {
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_win_show(plugin_win, "called -> prof_get_current_muc: <none>");
|
|
||||||
}
|
|
||||||
} else if (strcmp(subject, "nick") == 0) {
|
|
||||||
create_win();
|
|
||||||
char *nick = prof_get_current_nick();
|
|
||||||
if (nick) {
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char *str = "called -> prof_get_current_nick: ";
|
|
||||||
char buf[strlen(str) + strlen(nick)];
|
|
||||||
sprintf(buf, "%s%s", str, nick);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else {
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_win_show(plugin_win, "called -> prof_get_current_nick: <none>");
|
|
||||||
}
|
|
||||||
} else if (strcmp(subject, "occupants") == 0) {
|
|
||||||
create_win();
|
|
||||||
char **occupants = prof_get_current_occupants();
|
|
||||||
if (occupants) {
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_win_show(plugin_win, "called -> prof_get_current_occupants:");
|
|
||||||
int i = 0;
|
|
||||||
while(occupants[i] != NULL) {
|
|
||||||
prof_win_show(plugin_win, occupants[i]);
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_win_show(plugin_win, "called -> prof_get_current_occupants: <none>");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
logmsg(char *level, char *msg)
|
|
||||||
{
|
|
||||||
if (level == NULL || msg == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(level, "debug") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_log_debug(msg);
|
|
||||||
char *str = "called -> prof_log_debug: ";
|
|
||||||
char buf[strlen(str) + strlen(msg)];
|
|
||||||
sprintf(buf, "%s%s", str, msg);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else if (strcmp(level, "info") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_log_info(msg);
|
|
||||||
char *str = "called -> prof_log_info: ";
|
|
||||||
char buf[strlen(str) + strlen(msg)];
|
|
||||||
sprintf(buf, "%s%s", str, msg);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else if (strcmp(level, "warning") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_log_warning(msg);
|
|
||||||
char *str = "called -> prof_log_warning: ";
|
|
||||||
char buf[strlen(str) + strlen(msg)];
|
|
||||||
sprintf(buf, "%s%s", str, msg);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else if (strcmp(level, "error") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_log_error(msg);
|
|
||||||
char *str = "called -> prof_log_error: ";
|
|
||||||
char buf[strlen(str) + strlen(msg)];
|
|
||||||
sprintf(buf, "%s%s", str, msg);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
docount(void)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char buf[100];
|
|
||||||
sprintf(buf, "Count: %d", count);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
doping(char *jid)
|
|
||||||
{
|
|
||||||
if (jid == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char *strstart = "<iq to='";
|
|
||||||
char *strend = "' type='get'><ping xmlns='urn:xmpp:ping'/></iq>";
|
|
||||||
char *idstart = "' id='cplugin-";
|
|
||||||
char idbuf[strlen(idstart) + 10];
|
|
||||||
sprintf(idbuf, "%s%d", idstart, ping_id);
|
|
||||||
char buf[strlen(strstart) + strlen(jid) + strlen(idbuf) + strlen(strend)];
|
|
||||||
sprintf(buf, "%s%s%s%s", strstart, jid, idbuf, strend);
|
|
||||||
int res = prof_send_stanza(buf);
|
|
||||||
ping_id++;
|
|
||||||
if (res) {
|
|
||||||
prof_win_show(plugin_win, "Ping sent successfully");
|
|
||||||
} else {
|
|
||||||
prof_win_show(plugin_win, "Error sending ping");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
booleansetting(char *op, char *group, char *key, char *value_str)
|
|
||||||
{
|
|
||||||
if (op == NULL || group == NULL || key == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((strcmp(op, "get") != 0) && (strcmp(op, "set") != 0)) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((strcmp(op, "set") == 0) && (strcmp(value_str, "true") != 0) && (strcmp(value_str, "false") != 0)) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(op, "get") == 0) {
|
|
||||||
int dflt = 0;
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
int res = prof_settings_get_boolean(group, key, dflt);
|
|
||||||
if (res) {
|
|
||||||
prof_win_show(plugin_win, "Boolean setting: TRUE");
|
|
||||||
} else {
|
|
||||||
prof_win_show(plugin_win, "Boolean setting: FALSE");
|
|
||||||
}
|
|
||||||
} else if (strcmp(op, "set") == 0) {
|
|
||||||
int value = 0;
|
|
||||||
if (strcmp(value_str, "true") == 0) {
|
|
||||||
value = 1;
|
|
||||||
}
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_settings_set_boolean(group, key, value);
|
|
||||||
char buf[5 + strlen(group) + 2 + strlen(key) + 4 + strlen(value_str)];
|
|
||||||
sprintf(buf, "Set [%s] %s to %s", group, key, value_str);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
stringsetting(char *op, char *group, char *key, char *value)
|
|
||||||
{
|
|
||||||
if (op == NULL || group == NULL || key == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((strcmp(op, "get") != 0) && (strcmp(op, "set") != 0)) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((strcmp(op, "set") == 0) && (value == NULL)) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(op, "get") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char *res = prof_settings_get_string(group, key, NULL);
|
|
||||||
if (res) {
|
|
||||||
char buf[16 + strlen(res)];
|
|
||||||
sprintf(buf, "String setting: %s", res);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else {
|
|
||||||
prof_win_show(plugin_win, "String setting: NULL");
|
|
||||||
}
|
|
||||||
} else if (strcmp(op, "set") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
prof_settings_set_string(group, key, value);
|
|
||||||
char buf[5 + strlen(group) + 2 + strlen(key) + 4 + strlen(value)];
|
|
||||||
sprintf(buf, "Set [%s] %s to %s", group, key, value);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
intsetting(char *op, char *group, char *key, char *value)
|
|
||||||
{
|
|
||||||
if (op == NULL || group == NULL || key == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((strcmp(op, "get") != 0) && (strcmp(op, "set") != 0)) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(op, "get") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
int res = prof_settings_get_int(group, key, 0);
|
|
||||||
char buf[256];
|
|
||||||
sprintf(buf, "Integer setting: %d", res);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else if (strcmp(op, "set") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
int int_value = atoi(value);
|
|
||||||
prof_settings_set_int(group, key, int_value);
|
|
||||||
char buf[256];
|
|
||||||
sprintf(buf, "Set [%s] %s to %d", group, key, int_value);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
incomingmsg(char *barejid, char *resource, char *message)
|
|
||||||
{
|
|
||||||
prof_incoming_message(barejid, resource, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
completer(char *op, char *item)
|
|
||||||
{
|
|
||||||
if (item == NULL) {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(op, "add") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char *ac[] = { item, NULL };
|
|
||||||
prof_completer_add("/c-test", ac);
|
|
||||||
char buf[256];
|
|
||||||
sprintf(buf, "Added \"%s\" to /c-test completer", item);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
prof_completer_add("/c-test completer remove", ac);
|
|
||||||
} else if (strcmp(op, "remove") == 0) {
|
|
||||||
create_win();
|
|
||||||
prof_win_focus(plugin_win);
|
|
||||||
char *ac[] = { item, NULL };
|
|
||||||
prof_completer_remove("/c-test", ac);
|
|
||||||
char buf[256];
|
|
||||||
sprintf(buf, "Removed \"%s\" from /c-test completer", item);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
prof_completer_remove("/c-test completer remove", ac);
|
|
||||||
} else {
|
|
||||||
prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
cmd_ctest(char **args)
|
|
||||||
{
|
|
||||||
if (strcmp(args[0], "consalert") == 0) consalert();
|
|
||||||
else if (strcmp(args[0], "consshow") == 0) consshow(args[1]);
|
|
||||||
else if (strcmp(args[0], "consshow_t") == 0) consshow_t(args[1], args[2], args[3], args[4]);
|
|
||||||
else if (strcmp(args[0], "constest") == 0) constest();
|
|
||||||
else if (strcmp(args[0], "winshow") == 0) winshow(args[1]);
|
|
||||||
else if (strcmp(args[0], "winshow_t") == 0) winshow_t(args[1], args[2], args[3], args[4]);
|
|
||||||
else if (strcmp(args[0], "sendline") == 0) sendline(args[1]);
|
|
||||||
else if (strcmp(args[0], "notify") == 0) donotify(args[1]);
|
|
||||||
else if (strcmp(args[0], "get") == 0) getsubject(args[1]);
|
|
||||||
else if (strcmp(args[0], "log") == 0) logmsg(args[1], args[2]);
|
|
||||||
else if (strcmp(args[0], "count") == 0) docount();
|
|
||||||
else if (strcmp(args[0], "ping") == 0) doping(args[1]);
|
|
||||||
else if (strcmp(args[0], "boolean") == 0) booleansetting(args[1], args[2], args[3], args[4]);
|
|
||||||
else if (strcmp(args[0], "string") == 0) stringsetting(args[1], args[2], args[3], args[4]);
|
|
||||||
else if (strcmp(args[0], "int") == 0) intsetting(args[1], args[2], args[3], args[4]);
|
|
||||||
else if (strcmp(args[0], "incoming") == 0) incomingmsg(args[1], args[2], args[3]);
|
|
||||||
else if (strcmp(args[0], "completer") == 0) completer(args[1], args[2]);
|
|
||||||
else prof_cons_bad_cmd_usage("/c-test");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
timed_callback(void)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
prof_win_show(plugin_win, "timed -> timed_callback called");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_init(const char * const version, const char * const status, const char *const account_name, const char *const fulljid)
|
|
||||||
{
|
|
||||||
pthread_create(&worker_thread, NULL, inc_counter, NULL);
|
|
||||||
|
|
||||||
prof_disco_add_feature("urn:xmpp:profanity:c_test_plugin");
|
|
||||||
|
|
||||||
prof_win_create(plugin_win, handle_win_input);
|
|
||||||
|
|
||||||
char buf[256];
|
|
||||||
if (account_name != NULL && fulljid != NULL) {
|
|
||||||
sprintf(buf, "fired -> prof_init: %s, %s, %s, %s", version, status, account_name, fulljid);
|
|
||||||
} else {
|
|
||||||
sprintf(buf, "fired -> prof_init: %s, %s", version, status);
|
|
||||||
}
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
const char *synopsis[] = {
|
|
||||||
"/c-test consalert",
|
|
||||||
"/c-test consshow <message>",
|
|
||||||
"/c-test consshow_t <group> <key> <default> <message>",
|
|
||||||
"/c-test constest",
|
|
||||||
"/c-test winshow <message>",
|
|
||||||
"/c-test winshow_t <group> <key> <default> <message>",
|
|
||||||
"/c-test notify <message>",
|
|
||||||
"/c-test sendline <line>",
|
|
||||||
"/c-test get recipient|room|nick|occupants",
|
|
||||||
"/c-test log debug|info|warning|error <message>",
|
|
||||||
"/c-test count",
|
|
||||||
"/c-test ping <jid>",
|
|
||||||
"/c-test boolean get <group> <key>",
|
|
||||||
"/c-test boolean set <group> <key> <value>",
|
|
||||||
"/c-test string get <group> <key>",
|
|
||||||
"/c-test string set <group> <key> <value>",
|
|
||||||
"/c-test int get <group> <key>",
|
|
||||||
"/c-test int set <group> <key> <value>",
|
|
||||||
"/c-test incoming <barejid> <resource> <message>",
|
|
||||||
"/c-test completer add|remove <item>",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
const char *description = "C test plugin. All commands focus the plugin window.";
|
|
||||||
const char *args[][2] = {
|
|
||||||
{ "consalert", "Highlight the console window in the status bar" },
|
|
||||||
{ "consshow <message>", "Show the message in the console window" },
|
|
||||||
{ "consshow_t <group> <key> <default> <message>", "Show the themed message in the console window. " },
|
|
||||||
{ "constest", "Show whether the command was run in the console." },
|
|
||||||
{ "winshow <message>", "Show the message in the plugin window" },
|
|
||||||
{ "winshow_t <group> <key> <default> <message>", "Show the themed message in the plugin window. " },
|
|
||||||
{ "notify <message>", "Send a desktop notification with message" },
|
|
||||||
{ "sendline <line>", "Pass line to profanity to process" },
|
|
||||||
{ "get recipient", "Show the current chat recipient, if in a chat window" },
|
|
||||||
{ "get room", "Show the current room JID, if in a chat room" },
|
|
||||||
{ "get nick", "Show nickname in current room, if in a chat room" },
|
|
||||||
{ "get occupants", "Show occupants in current room, if in a chat room" },
|
|
||||||
{ "log debug|info|warning|error <message>", "Log a message at the specified level" },
|
|
||||||
{ "count", "Show the counter, incremented every 5 seconds by a worker thread" },
|
|
||||||
{ "ping <jid>", "Send an XMPP ping to the specified Jabber ID" },
|
|
||||||
{ "boolean get <group> <key>", "Get a boolean setting" },
|
|
||||||
{ "boolean set <group> <key> <value>", "Set a boolean setting" },
|
|
||||||
{ "string get <group> <key>", "Get a string setting" },
|
|
||||||
{ "string set <group> <key> <value>", "Set a string setting" },
|
|
||||||
{ "int get <group> <key>", "Get a integer setting" },
|
|
||||||
{ "int set <group> <key> <value>", "Set a integer setting" },
|
|
||||||
{ "incoming <barejid> <resource> <message>", "Show an incoming message." },
|
|
||||||
{ "completer add <item>", "Add an autocomplete item to the /c-test command." },
|
|
||||||
{ "completer remove <item>", "Remove an autocomplete item from the /c-test command." },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
const char *examples[] = {
|
|
||||||
"/c-test sendline /about",
|
|
||||||
"/c-test log debug \"Test debug message\"",
|
|
||||||
"/c-test consshow_t c-test cons.show none \"This is themed\"",
|
|
||||||
"/c-test consshow_t none none bold_cyan \"This is bold_cyan\"",
|
|
||||||
"/c-test ping buddy@server.org",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
prof_register_command("/c-test", 1, 5, synopsis, description, args, examples, cmd_ctest);
|
|
||||||
|
|
||||||
char *cmd_ac[] = {
|
|
||||||
"consalert",
|
|
||||||
"consshow",
|
|
||||||
"consshow_t",
|
|
||||||
"constest",
|
|
||||||
"winshow",
|
|
||||||
"winshow_t",
|
|
||||||
"notify",
|
|
||||||
"sendline",
|
|
||||||
"get",
|
|
||||||
"log",
|
|
||||||
"count",
|
|
||||||
"ping",
|
|
||||||
"boolean",
|
|
||||||
"string",
|
|
||||||
"int",
|
|
||||||
"incoming",
|
|
||||||
"completer",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
prof_completer_add("/c-test", cmd_ac);
|
|
||||||
|
|
||||||
char *get_ac[] = { "recipient", "room", "nick", "occupants", NULL };
|
|
||||||
prof_completer_add("/c-test get", get_ac);
|
|
||||||
|
|
||||||
char *log_ac[] = { "debug", "info", "warning", "error", NULL };
|
|
||||||
prof_completer_add("/c-test log", log_ac);
|
|
||||||
|
|
||||||
char *boolean_ac[] = { "get", "set", NULL };
|
|
||||||
prof_completer_add("/c-test boolean", boolean_ac);
|
|
||||||
|
|
||||||
char *string_ac[] = { "get", "set", NULL };
|
|
||||||
prof_completer_add("/c-test string", string_ac);
|
|
||||||
|
|
||||||
char *int_ac[] = { "get", "set", NULL };
|
|
||||||
prof_completer_add("/c-test int", int_ac);
|
|
||||||
|
|
||||||
char *completer_ac[] = { "add", "remove", NULL };
|
|
||||||
prof_completer_add("/c-test completer", completer_ac);
|
|
||||||
|
|
||||||
prof_register_timed(timed_callback, 30);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_on_start(void)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
prof_win_show(plugin_win, "fired -> prof_on_start");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_on_shutdown(void)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
prof_win_show(plugin_win, "fired -> prof_on_shutdown");
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_on_connect(const char * const account_name, const char * const fulljid)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_connect: ";
|
|
||||||
char buf[strlen(str) + strlen(account_name) + 2 + strlen(fulljid) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s", str, account_name, fulljid);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_on_disconnect(const char * const account_name, const char * const fulljid)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_disconnect: ";
|
|
||||||
char buf[strlen(str) + strlen(account_name) + 2 + strlen(fulljid) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s", str, account_name, fulljid);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
prof_pre_chat_message_display(const char * const jid, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_pre_chat_message_display: ";
|
|
||||||
char buf[strlen(str) + strlen(jid) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s", str, jid, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_post_chat_message_display(const char * const jid, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_post_chat_message_display: ";
|
|
||||||
char buf[strlen(str) + strlen(jid) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s", str, jid, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
prof_pre_chat_message_send(const char * const jid, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_pre_chat_message_send: ";
|
|
||||||
char buf[strlen(str) + strlen(jid) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s", str, jid, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_post_chat_message_send(const char * const jid, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_post_chat_message_send: ";
|
|
||||||
char buf[strlen(str) + strlen(jid) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s", str, jid, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
prof_pre_room_message_display(const char * const room, const char * const nick, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_pre_room_message_display: ";
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(nick) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s, %s", str, room, nick, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_post_room_message_display(const char * const room, const char * const nick, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_post_room_message_display: ";
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(nick) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s, %s", str, room, nick, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
prof_pre_room_message_send(const char * const room, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_pre_room_message_send: ";
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s", str, room, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_post_room_message_send(const char * const room, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_post_room_message_send: ";
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s", str, room, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_on_room_history_message(const char * const room, const char *const nick, const char *const message, const char *const timestamp)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_room_history_message: ";
|
|
||||||
if (timestamp == NULL) {
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(nick) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s, %s", str, room, nick, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
} else {
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(nick) + 2 + strlen(message) + 2 + strlen(timestamp) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s, %s, %s", str, room, nick, message, timestamp);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
prof_pre_priv_message_display(const char * const room, const char * const nick, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_pre_priv_message_display: ";
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(nick) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s, %s", str, room, nick, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_post_priv_message_display(const char * const room, const char * const nick, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_post_priv_message_display: ";
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(nick) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s, %s", str, room, nick, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *
|
|
||||||
prof_pre_priv_message_send(const char * const room, const char * const nick, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_pre_priv_message_send: ";
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(nick) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s, %s", str, room, nick, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_post_priv_message_send(const char * const room, const char * const nick, const char *message)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_post_priv_message_send: ";
|
|
||||||
char buf[strlen(str) + strlen(room) + 2 + strlen(nick) + 2 + strlen(message) + 1];
|
|
||||||
sprintf(buf, "%s%s, %s, %s", str, room, nick, message);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
prof_on_message_stanza_send(const char *const stanza)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_message_stanza_send: ";
|
|
||||||
char buf[strlen(str) + strlen(stanza) + 1];
|
|
||||||
sprintf(buf, "%s%s", str, stanza);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
// char *new_stanza = strdup("<message id='ktx72v49' to='chanleemoon@ejabberd.local' type='chat' xml:lang='en'><body>Art thou not Romeo, and a Montague?</body></message>");
|
|
||||||
// return (char *)new_stanza;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
prof_on_message_stanza_receive(const char *const stanza)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_message_stanza_receive: ";
|
|
||||||
char buf[strlen(str) + strlen(stanza) + 1];
|
|
||||||
sprintf(buf, "%s%s", str, stanza);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
prof_on_presence_stanza_send(const char *const stanza)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_presence_stanza_send: ";
|
|
||||||
char buf[strlen(str) + strlen(stanza) + 1];
|
|
||||||
sprintf(buf, "%s%s", str, stanza);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
prof_on_presence_stanza_receive(const char *const stanza)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_presence_stanza_receive: ";
|
|
||||||
char buf[strlen(str) + strlen(stanza) + 1];
|
|
||||||
sprintf(buf, "%s%s", str, stanza);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char*
|
|
||||||
prof_on_iq_stanza_send(const char *const stanza)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_iq_stanza_send: ";
|
|
||||||
char buf[strlen(str) + strlen(stanza) + 1];
|
|
||||||
sprintf(buf, "%s%s", str, stanza);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
prof_on_iq_stanza_receive(const char *const stanza)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_iq_stanza_receive: ";
|
|
||||||
char buf[strlen(str) + strlen(stanza) + 1];
|
|
||||||
sprintf(buf, "%s%s", str, stanza);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_on_contact_offline(const char *const barejid, const char *const resource, const char *const status)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_contact_offline: ";
|
|
||||||
int status_len = status == NULL ? 0 : strlen(status) + 2;
|
|
||||||
char buf[strlen(str) + strlen(barejid) + 1 + strlen(resource) + 1 + status_len + 1];
|
|
||||||
if (status) {
|
|
||||||
sprintf(buf, "%s%s/%s \"%s\"", str, barejid, resource, status);
|
|
||||||
} else {
|
|
||||||
sprintf(buf, "%s%s/%s", str, barejid, resource);
|
|
||||||
}
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_on_contact_presence(const char *const barejid, const char *const resource, const char *const presence, const char *const status, const int priority)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
|
|
||||||
char *str = "fired -> prof_on_contact_presence: ";
|
|
||||||
int status_len = status == NULL ? 0 : strlen(status) + 2;
|
|
||||||
char buf[strlen(str) + strlen(barejid) + 1 + strlen(resource) + 1 + strlen(presence) + 1 + 10 + status_len + 1];
|
|
||||||
if (status) {
|
|
||||||
sprintf(buf, "%s%s/%s %s %d \"%s\"", str, barejid, resource, presence, priority, status);
|
|
||||||
} else {
|
|
||||||
sprintf(buf, "%s%s/%s %s %d", str, barejid, resource, presence, priority);
|
|
||||||
}
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_on_chat_win_focus(const char *const barejid)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
char *str = "fired -> prof_on_chat_win_focus: ";
|
|
||||||
char buf[strlen(str) + strlen(barejid) + 1];
|
|
||||||
sprintf(buf, "%s%s", str, barejid);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
prof_on_room_win_focus(const char *const roomjid)
|
|
||||||
{
|
|
||||||
create_win();
|
|
||||||
char *str = "fired -> prof_on_room_win_focus: ";
|
|
||||||
char buf[strlen(str) + strlen(roomjid) + 1];
|
|
||||||
sprintf(buf, "%s%s", str, roomjid);
|
|
||||||
prof_win_show(plugin_win, buf);
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user