10 Commits

Author SHA1 Message Date
James Booth
035c190e1c Update test plugins 2017-01-28 19:48:51 +00:00
James Booth
1dcd915678 syscmd.py: Make newlines configurable
issue #9
2016-11-13 21:52:15 +00:00
James Booth
2132d79094 Update README 2016-11-13 17:29:09 +00:00
James Booth
5025312337 Update README 2016-11-13 17:27:01 +00:00
James Booth
cdb6cd93b5 Restructure project 2016-11-13 17:02:35 +00:00
James Booth
5eea0240ad paste.py: newline option only for multiline text
issue #5
2016-11-13 16:16:31 +00:00
James Booth
0d4dbd6fd1 paste,py: add newline option
issue #5
2016-11-13 15:40:33 +00:00
James Booth
3afb6bb157 sounds.py: don't play sounds on messages from self 2016-11-06 23:15:46 +00:00
James Booth
38cc929f86 Add filepath autocompletion to sounds.py 2016-10-10 23:32:31 +01:00
James Booth
144884d819 Update plugins to use filepath completion 2016-10-10 22:48:01 +01:00
25 changed files with 240 additions and 225 deletions

View File

@@ -1,59 +1,22 @@
profanity-plugins
=================
Plugin support for Profanity is currently in development.
* The `master` branch of Profanity now includes support for C and Python plugins.
* 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
* [Website documentation](http://www.profanity.im/plugins.html)
Building Profanity with plugin support
--------------------------------------
Additional dependencies required:
Dependencies required:
```
autoconf-archive
libtool
```
Plus the development packages for supported languages:
For Python plugins the following is also required:
```
python-dev
lua-dev
ruby-dev
```
Build with:
```
./bootstrap.sh
./configure
make
sudo make install
```
After building, run `profanity -v` to see which language support is available, example output:
```
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
@@ -62,51 +25,17 @@ Installing plugins
Use the `/plugins install` command, e.g.
```
/plugins install ~/projects-git/profanity-plugins/say.py
/plugins install ~/projects-git/profanity-plugins/stable/say.py
```
See the `/help plugins` command for further plugin management options.
More help on plugins
--------------------
Branches
--------
* `/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
```
Plugin settings
---------------
The plugins API also includes functions to read and write settings. The settings are stored in:
```
~/.local/share/profanity/plugin_settings
```
For example ([say.py](https://github.com/boothj5/profanity-plugins/blob/master/say.py) plugin):
```
[say]
args=-v english -s 120
enabled=active
```
* `0.5.0`: Maintenance branch for plugins compatible with the current Profanity release 0.5.0
* `0.5.1`: Development for the next Profanity patch release 0.5.1
* `master`: Development for the next Profanity major release 0.6.0
Developing plugins
------------------
@@ -117,10 +46,3 @@ API Documentation:
* [C API](http://www.profanity.im/plugins/c/html/profapi_8h.html)
* [C hooks](http://www.profanity.im/plugins/c/html/profhooks_8h.html)
Example test plugins (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)

View File

@@ -1,27 +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 presence_notify.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 ../..

View File

@@ -1,27 +0,0 @@
"""
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():
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)

View File

@@ -59,3 +59,4 @@ def prof_init(version, status, account_name, fulljid):
prof.register_command("/imgur", 1, 1, synopsis, description, args, examples, _cmd_imgur)
prof.completer_add("/imgur", [ "screenshot" ])
prof.filepath_completer_add("/imgur")

60
stable/paste.py Normal file
View 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" ])

View File

@@ -157,6 +157,9 @@ def prof_init(version, status, account_name, fulljid):
prof.completer_add("/sounds set", [ "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):
@@ -172,6 +175,13 @@ def prof_post_chat_message_display(barejid, resource, message):
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

129
stable/syscmd.py Normal file
View 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)
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" ])

View File

@@ -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" ])

View File

@@ -128,6 +128,10 @@ def _get(subject):
if room:
prof.win_focus(plugin_win)
prof.win_show(plugin_win, "called -> prof_get_current_muc: " + room)
nick = prof.get_room_nick(room)
if nick:
prof.win_focus(plugin_win)
prof.win_show(plugin_win, "called -> prof_get_room_nick('" + room + "'): " + nick)
else:
prof.win_focus(plugin_win)
prof.win_show(plugin_win, "called -> prof_get_current_muc: <none>")
@@ -442,7 +446,8 @@ def prof_init(version, status, account_name, fulljid):
"/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>"
"/python-test completer add|remove <item>",
"/python-test file"
]
description = "Python test plugins. All commands focus the plugin window."
args = [
@@ -473,7 +478,8 @@ def prof_init(version, status, account_name, fulljid):
[ "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." ]
[ "completer remove <item>", "Remove an autocomplete item from the /c-test command." ],
[ "file", "Complete a file path." ]
]
examples = [
"/python-test sendline /about",
@@ -504,7 +510,8 @@ def prof_init(version, status, account_name, fulljid):
"string_list",
"int",
"incoming",
"completer"
"completer",
"file"
]
)
prof.completer_add("/python-test get",
@@ -529,6 +536,8 @@ def prof_init(version, status, account_name, fulljid):
[ "add", "remove" ]
)
prof.filepath_completer_add("/python-test file")
prof.register_timed(timed_callback, 5)
@@ -578,6 +587,7 @@ def prof_post_chat_message_display(barejid, resource, message):
def prof_pre_chat_message_send(barejid, message):
prof.win_create(plugin_win, _handle_win_input)
prof.win_show(plugin_win, "fired -> prof_pre_chat_message_send: " + barejid + ", " + message)
return message
def prof_post_chat_message_send(barejid, message):
@@ -598,6 +608,7 @@ def prof_post_room_message_display(barejid, nick, message):
def prof_pre_room_message_send(barejid, message):
prof.win_create(plugin_win, _handle_win_input)
prof.win_show(plugin_win, "fired -> prof_pre_room_message_send: " + barejid + ", " + message)
return message
def prof_post_room_message_send(barejid, message):
@@ -626,6 +637,7 @@ def prof_post_priv_message_display(barejid, nick, message):
def prof_pre_priv_message_send(barejid, nick, message):
prof.win_create(plugin_win, _handle_win_input)
prof.win_show(plugin_win, "fired -> prof_pre_priv_message_send: " + barejid + ", " + nick + ", " + message)
return message
def prof_post_priv_message_send(barejid, nick, message):

View File

@@ -185,6 +185,15 @@ getsubject(char *subject)
char buf[strlen(str) + strlen(room)];
sprintf(buf, "%s%s", str, room);
prof_win_show(plugin_win, buf);
char *nick = prof_get_room_nick(room);
if (nick) {
prof_win_focus(plugin_win);
char *str1 = "called -> prof_get_room_nick('";
char *str2 = "'): ";
char buf1[strlen(str1) + strlen(room) + strlen(str2) + strlen(nick)];
sprintf(buf1, "%s%s%s%s", str1, room, str2, nick);
prof_win_show(plugin_win, buf1);
}
} else {
prof_win_focus(plugin_win);
prof_win_show(plugin_win, "called -> prof_get_current_muc: <none>");
@@ -605,6 +614,7 @@ prof_init(const char * const version, const char * const status, const char *con
"/c-test int set <group> <key> <value>",
"/c-test incoming <barejid> <resource> <message>",
"/c-test completer add|remove <item>",
"/c-test file",
NULL
};
char *description = "C test plugin. All commands focus the plugin window.";
@@ -637,6 +647,7 @@ prof_init(const char * const version, const char * const status, const char *con
{ "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." },
{ "file", "Complete a file path." },
{ NULL, NULL }
};
@@ -670,6 +681,7 @@ prof_init(const char * const version, const char * const status, const char *con
"int",
"incoming",
"completer",
"file",
NULL
};
prof_completer_add("/c-test", cmd_ac);
@@ -695,6 +707,8 @@ prof_init(const char * const version, const char * const status, const char *con
char *completer_ac[] = { "add", "remove", NULL };
prof_completer_add("/c-test completer", completer_ac);
prof_filepath_completer_add("/c-test file");
prof_register_timed(timed_callback, 5);
}
@@ -777,7 +791,7 @@ prof_pre_chat_message_send(const char * const barejid, const char *message)
sprintf(buf, "%s%s, %s", str, barejid, message);
prof_win_show(plugin_win, buf);
return NULL;
return strdup(message);
}
void
@@ -825,7 +839,7 @@ prof_pre_room_message_send(const char * const barejid, const char *message)
sprintf(buf, "%s%s, %s", str, barejid, message);
prof_win_show(plugin_win, buf);
return NULL;
return strdup(message);
}
void
@@ -890,7 +904,7 @@ prof_pre_priv_message_send(const char * const barejid, const char * const nick,
sprintf(buf, "%s%s, %s, %s", str, barejid, nick, message);
prof_win_show(plugin_win, buf);
return NULL;
return strdup(message);
}
void