mirror of
https://github.com/Tha14/toxic.git
synced 2024-11-14 05:23:01 +01:00
Merge branch 'TsarFox-master'
This commit is contained in:
commit
6d3fbfee59
1
.gitignore
vendored
1
.gitignore
vendored
@ -16,3 +16,4 @@ stamp-h1
|
||||
build/toxic
|
||||
build/*.o
|
||||
build/*.d
|
||||
apidoc/python/build
|
||||
|
@ -20,6 +20,7 @@
|
||||
| [OpenAL](http://openal.org) | AUDIO, SOUND NOTIFICATIONS | libopenal-dev |
|
||||
| [OpenALUT](http://openal.org) | SOUND NOTIFICATIONS | libalut-dev |
|
||||
| [LibNotify](https://developer.gnome.org/libnotify) | DESKTOP NOTIFICATIONS | libnotify-dev |
|
||||
| [Python 3](http://www.python.org/) | PYTHON | python3-dev |
|
||||
| [AsciiDoc](http://asciidoc.org/index.html) | DOCUMENTATION<sup>1</sup> | asciidoc |
|
||||
|
||||
<sup>1</sup>: see [Documentation](#documentation)
|
||||
@ -55,6 +56,8 @@ Run `make doc` in the build directory after editing the asciidoc files to regene
|
||||
* `DISABLE_AV=1` → build toxic without audio call support
|
||||
* `DISABLE_SOUND_NOTIFY=1` → build toxic without sound notifications support
|
||||
* `DISABLE_DESKTOP_NOTIFY=1` → build toxic without desktop notifications support
|
||||
* Features excluded from the default build must be explicitly enabled using special variables:
|
||||
* `ENABLE_PYTHON=1` → build toxic with Python scripting support
|
||||
|
||||
#### Packaging
|
||||
* For packaging purpose, you can use `DESTDIR=""` to specify a directory where to store installed files
|
||||
|
20
apidoc/python/Makefile
Normal file
20
apidoc/python/Makefile
Normal file
@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXPROJ = toxic_api
|
||||
SOURCEDIR = source
|
||||
BUILDDIR = build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
157
apidoc/python/source/conf.py
Normal file
157
apidoc/python/source/conf.py
Normal file
@ -0,0 +1,157 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# toxic_api documentation build configuration file, created by
|
||||
# sphinx-quickstart on Tue May 16 08:58:24 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
# containing dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
# import os
|
||||
# import sys
|
||||
# sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#
|
||||
# needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = []
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix(es) of source filenames.
|
||||
# You can specify multiple suffix as a list of string:
|
||||
#
|
||||
# source_suffix = ['.rst', '.md']
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'toxic_api'
|
||||
copyright = '2017, Jakob Kreuze'
|
||||
author = 'Jakob Kreuze'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.7.2'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.7.2'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This patterns also effect to html_static_path and html_extra_path
|
||||
exclude_patterns = []
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# If true, `todo` and `todoList` produce output, else they produce nothing.
|
||||
todo_include_todos = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'alabaster'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#
|
||||
# html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'toxic_apidoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#
|
||||
# 'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#
|
||||
# 'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#
|
||||
# 'preamble': '',
|
||||
|
||||
# Latex figure (float) alignment
|
||||
#
|
||||
# 'figure_align': 'htbp',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'toxic_api.tex', 'toxic\\_api Documentation',
|
||||
'Jakob Kreuze', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'toxic_api', 'toxic_api Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'toxic_api', 'toxic_api Documentation',
|
||||
author, 'toxic_api', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
|
||||
|
8
apidoc/python/source/examples.rst
Normal file
8
apidoc/python/source/examples.rst
Normal file
@ -0,0 +1,8 @@
|
||||
============
|
||||
API Examples
|
||||
============
|
||||
|
||||
Fortune
|
||||
=======
|
||||
.. literalinclude:: fortune.py
|
||||
:language: python
|
37
apidoc/python/source/fortune.py
Normal file
37
apidoc/python/source/fortune.py
Normal file
@ -0,0 +1,37 @@
|
||||
import toxic_api
|
||||
import random
|
||||
|
||||
FORTUNES = [
|
||||
"A bug in the code is worth two in the documentation.",
|
||||
"A bug in the hand is better than one as yet undetected.",
|
||||
"\"A debugged program is one for which you have not yet found the "
|
||||
"conditions that make it fail.\" -- Jerry Ogdin"
|
||||
]
|
||||
|
||||
def send_fortune(args):
|
||||
"""Callback function that sends the contact of the current window a
|
||||
given number of random fortunes.
|
||||
"""
|
||||
if len(args) != 1:
|
||||
toxic_api.display("Only one argument allowed!")
|
||||
return
|
||||
|
||||
try:
|
||||
count = int(args[0])
|
||||
except ValueError:
|
||||
toxic_api.display("Argument must be a number!")
|
||||
return
|
||||
|
||||
if count < 0 or count > 20:
|
||||
toxic_api.display("Argument is too large!")
|
||||
return
|
||||
|
||||
name = toxic_api.get_nick()
|
||||
|
||||
toxic_api.send("%s has decided to send you %d fortunes:" % (name, count))
|
||||
for _ in range(count):
|
||||
toxic_api.send(random.choice(FORTUNES))
|
||||
|
||||
|
||||
toxic_api.register("/fortune", "Send a fortune to the contact of the current "
|
||||
"window", send_fortune)
|
9
apidoc/python/source/index.rst
Normal file
9
apidoc/python/source/index.rst
Normal file
@ -0,0 +1,9 @@
|
||||
Toxic Scripting Interface Documentation
|
||||
=======================================
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
intro
|
||||
reference
|
||||
examples
|
12
apidoc/python/source/intro.rst
Normal file
12
apidoc/python/source/intro.rst
Normal file
@ -0,0 +1,12 @@
|
||||
=========================
|
||||
Toxic Scripting Interface
|
||||
=========================
|
||||
|
||||
A Python scripting interface to `Toxic <https://github.com/JFreegman/toxic>`_.
|
||||
|
||||
|
||||
Getting Started
|
||||
===============
|
||||
Toxic is compiled with Python support by default. To access the scripting interface, simply import "toxic_api" in your script.
|
||||
|
||||
Scripts can be run by issuing "/run <path>" from toxic, or placing them in the "autorun_path" from your toxic configuration file.
|
73
apidoc/python/source/reference.rst
Normal file
73
apidoc/python/source/reference.rst
Normal file
@ -0,0 +1,73 @@
|
||||
=============
|
||||
API Reference
|
||||
=============
|
||||
|
||||
Messages
|
||||
========
|
||||
.. function:: display(msg)
|
||||
|
||||
Display a message to the user through the current window.
|
||||
|
||||
:param msg: The message to display.
|
||||
:type msg: string
|
||||
:rtype: none
|
||||
|
||||
.. function:: send(msg)
|
||||
|
||||
Send a message to the user specified by the currently open conversation.
|
||||
|
||||
:param msg: The message to display.
|
||||
:type msg: string
|
||||
:rtype: none
|
||||
|
||||
|
||||
State
|
||||
=====
|
||||
.. function:: get_nick()
|
||||
|
||||
Return the user's current nickname.
|
||||
|
||||
:rtype: string
|
||||
|
||||
.. function:: get_status()
|
||||
|
||||
Return a string representing the user's current status. Can be either "online", "away", or "busy".
|
||||
|
||||
:rtype: string
|
||||
|
||||
.. function:: get_status_message()
|
||||
|
||||
Return the user's current status message.
|
||||
|
||||
:rtype: string
|
||||
|
||||
.. function:: get_all_friends()
|
||||
|
||||
Return a list of all the user's friends.
|
||||
|
||||
:rtype: list of (string, string) tuples containing the nickname followed by their public key
|
||||
|
||||
|
||||
Commands
|
||||
========
|
||||
.. function:: execute(command, class)
|
||||
|
||||
Executes the given command. The API exports three constants for the class parameter; GLOBAL_COMMAND, CHAT_COMMAND, and GROUPCHAT_COMMAND.
|
||||
|
||||
:param command: The command to execute.
|
||||
:type command: string
|
||||
:param class: The class of the command.
|
||||
:type class: int
|
||||
:rtype: none
|
||||
|
||||
.. function:: register(command, help, callback)
|
||||
|
||||
Register a callback to be executed whenever command is run. The callback function will be called with one argument, a list of arguments from when the user calls the command.
|
||||
|
||||
:param command: The command to listen for.
|
||||
:type command: string
|
||||
:param help: A description of the command to be shown in the help menu.
|
||||
:type help: string
|
||||
:param callback: The function to be called.
|
||||
:type callback: callable
|
||||
:rtype: none
|
@ -18,4 +18,4 @@ else ifneq ($(MAKECMDGOALS), clean)
|
||||
$(warning WARNING -- Toxic will be compiled without audio support)
|
||||
$(warning WARNING -- You need these libraries for audio support)
|
||||
$(warning WARNING -- $(MISSING_AUDIO_LIBS))
|
||||
endif
|
||||
endif
|
||||
|
@ -40,6 +40,12 @@ ifneq ($(QR_PNG), disabled)
|
||||
-include $(CHECKS_DIR)/qr_png.mk
|
||||
endif
|
||||
|
||||
# Check if we want build Python scripting support
|
||||
PYTHON = $(shell if [ -z "$(ENABLE_PYTHON)" ] || [ "$(ENABLE_PYTHON)" = "0" ] ; then echo disabled ; else echo enabled ; fi)
|
||||
ifneq ($(PYTHON), disabled)
|
||||
-include $(CHECKS_DIR)/python.mk
|
||||
endif
|
||||
|
||||
# Check if we can build Toxic
|
||||
CHECK_LIBS = $(shell $(PKG_CONFIG) --exists $(LIBS) || echo -n "error")
|
||||
ifneq ($(CHECK_LIBS), error)
|
||||
|
15
cfg/checks/python.mk
Normal file
15
cfg/checks/python.mk
Normal file
@ -0,0 +1,15 @@
|
||||
# Variables for Python scripting support
|
||||
PYTHON3_LIBS = python3
|
||||
PYTHON_CFLAGS = -DPYTHON
|
||||
PYTHON_OBJ = api.o python_api.o
|
||||
|
||||
# Check if we can build Python scripting support
|
||||
CHECK_PYTHON3_LIBS = $(shell $(PKG_CONFIG) --exists $(PYTHON3_LIBS) || echo -n "error")
|
||||
ifneq ($(CHECK_PYTHON3_LIBS), error)
|
||||
LDFLAGS += $(shell python3-config --ldflags)
|
||||
CFLAGS += $(PYTHON_CFLAGS) $(shell python3-config --includes)
|
||||
OBJ += $(PYTHON_OBJ)
|
||||
else ifneq ($(MAKECMDGOALS), clean)
|
||||
$(warning WARNING -- Toxic will be compiled without Python scripting support)
|
||||
$(warning WARNING -- You need python3 installed for Python scripting support)
|
||||
endif
|
@ -15,6 +15,7 @@ help:
|
||||
@echo " DISABLE_SOUND_NOTIFY: Set to \"1\" to force building without sound notification support"
|
||||
@echo " DISABLE_DESKTOP_NOTIFY: Set to \"1\" to force building without desktop notifications support"
|
||||
@echo " DISABLE_QRPNG: Set to \"1\" to force building without QR exported as PNG support"
|
||||
@echo " ENABLE_PYTHON: Set to \"1\" to enable building with Python scripting support"
|
||||
@echo " USER_CFLAGS: Add custom flags to default CFLAGS"
|
||||
@echo " USER_LDFLAGS: Add custom flags to default LDFLAGS"
|
||||
@echo " PREFIX: Specify a prefix directory for binaries, data files,... (default is \"$(abspath $(PREFIX))\")"
|
||||
|
@ -1,13 +1,13 @@
|
||||
'\" t
|
||||
.\" Title: toxic.conf
|
||||
.\" Author: [see the "AUTHORS" section]
|
||||
.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
|
||||
.\" Date: 2016-07-21
|
||||
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
||||
.\" Date: 2016-09-20
|
||||
.\" Manual: Toxic Manual
|
||||
.\" Source: toxic __VERSION__
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "TOXIC\&.CONF" "5" "2016\-07\-21" "toxic __VERSION__" "Toxic Manual"
|
||||
.TH "TOXIC\&.CONF" "5" "2016\-09\-20" "toxic __VERSION__" "Toxic Manual"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
@ -227,6 +227,11 @@ Default path for downloads\&. String value\&. Absolute path for downloaded files
|
||||
Path for your avatar (file must be a \&.png and cannot exceed 16\&.3 KiB)
|
||||
.RE
|
||||
.PP
|
||||
\fBautorun_path\fR
|
||||
.RS 4
|
||||
Path for any scripts that should be run on startup
|
||||
.RE
|
||||
.PP
|
||||
\fBchatlogs_path\fR
|
||||
.RS 4
|
||||
Default path for chatlogs\&. String value\&. Absolute path for chatlog files\&.
|
||||
|
@ -143,6 +143,9 @@ OPTIONS
|
||||
*avatar_path*;;
|
||||
Path for your avatar (file must be a .png and cannot exceed 16.3 KiB)
|
||||
|
||||
*autorun_path*;;
|
||||
Path for any scripts that should be run on startup
|
||||
|
||||
*chatlogs_path*;;
|
||||
Default path for chatlogs. String value. Absolute path for chatlog files.
|
||||
|
||||
|
@ -87,6 +87,9 @@ tox = {
|
||||
// Path for your avatar (file must be a .png and cannot exceed 64 KiB)
|
||||
// avatar_path="/home/USERNAME/Pictures/youravatar.png";
|
||||
|
||||
// Path for scripts that should be run on startup
|
||||
// autorun_path="/home/USERNAME/toxic_scripts/";
|
||||
|
||||
// Path for chatlogs
|
||||
// chatlogs_path="/home/USERNAME/toxic_chatlogs/";
|
||||
};
|
||||
@ -118,4 +121,3 @@ keys = {
|
||||
toggle_peerlist="Ctrl+b";
|
||||
toggle_paste_mode="Ctrl+T";
|
||||
};
|
||||
|
||||
|
208
src/api.c
Normal file
208
src/api.c
Normal file
@ -0,0 +1,208 @@
|
||||
/* api.c
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <tox/tox.h>
|
||||
|
||||
#include "execute.h"
|
||||
#include "friendlist.h"
|
||||
#include "line_info.h"
|
||||
#include "message_queue.h"
|
||||
#include "misc_tools.h"
|
||||
#include "python_api.h"
|
||||
#include "settings.h"
|
||||
#include "toxic_strings.h"
|
||||
#include "windows.h"
|
||||
|
||||
Tox *user_tox;
|
||||
static WINDOW *cur_window;
|
||||
static ToxWindow *self_window;
|
||||
|
||||
extern FriendsList Friends;
|
||||
extern struct user_settings *user_settings;
|
||||
|
||||
void api_display(const char *const msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return;
|
||||
|
||||
self_window = get_active_window();
|
||||
line_info_add(self_window, NULL, NULL, NULL, SYS_MSG, 0, 0, msg);
|
||||
}
|
||||
|
||||
FriendsList api_get_friendslist(void)
|
||||
{
|
||||
return Friends;
|
||||
}
|
||||
|
||||
char *api_get_nick(void)
|
||||
{
|
||||
size_t len = tox_self_get_name_size(user_tox);
|
||||
uint8_t *name = malloc(len + 1);
|
||||
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
tox_self_get_name(user_tox, name);
|
||||
name[len] = '\0';
|
||||
return (char *) name;
|
||||
}
|
||||
|
||||
TOX_USER_STATUS api_get_status(void)
|
||||
{
|
||||
return tox_self_get_status(user_tox);
|
||||
}
|
||||
|
||||
char *api_get_status_message(void)
|
||||
{
|
||||
size_t len = tox_self_get_status_message_size(user_tox);
|
||||
uint8_t *status = malloc(len + 1);
|
||||
|
||||
if (status == NULL)
|
||||
return NULL;
|
||||
|
||||
tox_self_get_status_message(user_tox, status);
|
||||
status[len] = '\0';
|
||||
return (char *) status;
|
||||
}
|
||||
|
||||
void api_send(const char *msg)
|
||||
{
|
||||
if (msg == NULL || self_window->chatwin->cqueue == NULL)
|
||||
return;
|
||||
|
||||
char *name = api_get_nick();
|
||||
char timefrmt[TIME_STR_SIZE];
|
||||
|
||||
if (name == NULL)
|
||||
return;
|
||||
|
||||
self_window = get_active_window();
|
||||
get_time_str(timefrmt, sizeof(timefrmt));
|
||||
|
||||
strncpy((char *) self_window->chatwin->line, msg, sizeof(self_window->chatwin->line));
|
||||
add_line_to_hist(self_window->chatwin);
|
||||
line_info_add(self_window, timefrmt, name, NULL, OUT_MSG, 0, 0, "%s", msg);
|
||||
cqueue_add(self_window->chatwin->cqueue, msg, strlen(msg), OUT_MSG,
|
||||
self_window->chatwin->hst->line_end->id + 1);
|
||||
free(name);
|
||||
}
|
||||
|
||||
void api_execute(const char *input, int mode)
|
||||
{
|
||||
self_window = get_active_window();
|
||||
execute(cur_window, self_window, user_tox, input, mode);
|
||||
}
|
||||
|
||||
int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE])
|
||||
{
|
||||
return do_python_command(num_args, args);
|
||||
}
|
||||
|
||||
int num_registered_handlers(void)
|
||||
{
|
||||
return python_num_registered_handlers();
|
||||
}
|
||||
|
||||
int help_max_width(void)
|
||||
{
|
||||
return python_help_max_width();
|
||||
}
|
||||
|
||||
void draw_handler_help(WINDOW *win)
|
||||
{
|
||||
python_draw_handler_help(win);
|
||||
}
|
||||
|
||||
void cmd_run(WINDOW *window, ToxWindow *self, Tox *m, int argc, char (*argv)[MAX_STR_SIZE])
|
||||
{
|
||||
FILE *fp;
|
||||
const char *error_str;
|
||||
|
||||
cur_window = window;
|
||||
self_window = self;
|
||||
|
||||
if ( argc != 1 ) {
|
||||
if ( argc < 1 ) error_str = "Path must be specified!";
|
||||
else error_str = "Only one argument allowed!";
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
|
||||
return;
|
||||
}
|
||||
|
||||
fp = fopen(argv[1], "r");
|
||||
|
||||
if ( fp == NULL ) {
|
||||
error_str = "Path does not exist!";
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, error_str);
|
||||
return;
|
||||
}
|
||||
|
||||
run_python(fp, argv[1]);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void invoke_autoruns(WINDOW *window, ToxWindow *self)
|
||||
{
|
||||
struct dirent *dir;
|
||||
char abspath_buf[PATH_MAX + 1], err_buf[PATH_MAX + 1];
|
||||
size_t path_len;
|
||||
DIR *d;
|
||||
FILE *fp;
|
||||
|
||||
if (user_settings->autorun_path[0] == '\0')
|
||||
return;
|
||||
|
||||
d = opendir(user_settings->autorun_path);
|
||||
|
||||
if (d == NULL) {
|
||||
snprintf(err_buf, PATH_MAX + 1, "Autorun path does not exist: %s", user_settings->autorun_path);
|
||||
api_display(err_buf);
|
||||
return;
|
||||
}
|
||||
|
||||
cur_window = window;
|
||||
self_window = self;
|
||||
|
||||
while ((dir = readdir(d)) != NULL) {
|
||||
path_len = strlen(dir->d_name);
|
||||
|
||||
if (!strcmp(dir->d_name + path_len - 3, ".py")) {
|
||||
snprintf(abspath_buf, PATH_MAX + 1, "%s%s", user_settings->autorun_path, dir->d_name);
|
||||
fp = fopen(abspath_buf, "r");
|
||||
|
||||
if (fp == NULL) {
|
||||
snprintf(err_buf, PATH_MAX + 1, "Invalid path: %s", abspath_buf);
|
||||
api_display(err_buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
run_python(fp, abspath_buf);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(d);
|
||||
}
|
42
src/api.h
Normal file
42
src/api.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* api.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef API_H
|
||||
#define API_H
|
||||
|
||||
#include "friendlist.h"
|
||||
#include "windows.h"
|
||||
|
||||
void api_display(const char *const msg);
|
||||
FriendsList api_get_friendslist(void);
|
||||
char *api_get_nick(void);
|
||||
TOX_USER_STATUS api_get_status(void);
|
||||
char *api_get_status_message(void);
|
||||
void api_send(const char *msg);
|
||||
void api_execute(const char *input, int mode);
|
||||
int do_plugin_command(int num_args, char (*args)[MAX_STR_SIZE]);
|
||||
int num_registered_handlers(void);
|
||||
int help_max_width(void);
|
||||
void draw_handler_help(WINDOW *win);
|
||||
void invoke_autoruns(WINDOW *w, ToxWindow *self);
|
||||
|
||||
#endif /* #define API_H */
|
@ -110,6 +110,10 @@ int complete_line(ToxWindow *self, const void *list, int n_items, int size)
|
||||
bool dir_search = !strncmp(ubuf, "/sendfile", strlen("/sendfile"))
|
||||
|| !strncmp(ubuf, "/avatar", strlen("/avatar"));
|
||||
|
||||
#ifdef PYTHON
|
||||
dir_search = dir_search || !strncmp(ubuf, "/run", strlen("/run"));
|
||||
#endif
|
||||
|
||||
/* isolate substring from space behind pos to pos */
|
||||
char tmp[MAX_STR_SIZE];
|
||||
snprintf(tmp, sizeof(tmp), "%s", ubuf);
|
||||
|
22
src/chat.c
22
src/chat.c
@ -65,8 +65,12 @@ static void init_infobox(ToxWindow *self);
|
||||
static void kill_infobox(ToxWindow *self);
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef AUDIO
|
||||
#if defined(AUDIO) && defined(PYTHON)
|
||||
#define AC_NUM_CHAT_COMMANDS 31
|
||||
#elif AUDIO
|
||||
#define AC_NUM_CHAT_COMMANDS 30
|
||||
#elif PYTHON
|
||||
#define AC_NUM_CHAT_COMMANDS 23
|
||||
#else
|
||||
#define AC_NUM_CHAT_COMMANDS 22
|
||||
#endif /* AUDIO */
|
||||
@ -108,6 +112,12 @@ static const char chat_cmd_list[AC_NUM_CHAT_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/video" },
|
||||
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
{ "/run" },
|
||||
|
||||
#endif /* PYTHON */
|
||||
};
|
||||
|
||||
static void set_self_typingstatus(ToxWindow *self, Tox *m, bool is_typing)
|
||||
@ -931,7 +941,15 @@ static void chat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
diff = dir_match(self, m, ctx->line, L"/sendfile");
|
||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||
} else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
||||
}
|
||||
|
||||
#ifdef PYTHON
|
||||
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) {
|
||||
diff = dir_match(self, m, ctx->line, L"/run");
|
||||
}
|
||||
#endif
|
||||
|
||||
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
||||
const char status_cmd_list[3][8] = {
|
||||
{"online"},
|
||||
{"away"},
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include "line_info.h"
|
||||
#include "misc_tools.h"
|
||||
#include "notify.h"
|
||||
#include "api.h"
|
||||
|
||||
struct cmd_func {
|
||||
const char *name;
|
||||
@ -67,6 +68,9 @@ static struct cmd_func global_commands[] = {
|
||||
{ "/lsvdev", cmd_list_video_devices },
|
||||
{ "/svdev" , cmd_change_video_device },
|
||||
#endif /* VIDEO */
|
||||
#ifdef PYTHON
|
||||
{ "/run", cmd_run },
|
||||
#endif /* PYTHON */
|
||||
{ NULL, NULL },
|
||||
};
|
||||
|
||||
@ -193,5 +197,10 @@ void execute(WINDOW *w, ToxWindow *self, Tox *m, const char *input, int mode)
|
||||
if (do_command(w, self, m, num_args, global_commands, args) == 0)
|
||||
return;
|
||||
|
||||
#ifdef PYTHON
|
||||
if (do_plugin_command(num_args, args) == 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
line_info_add(self, NULL, NULL, NULL, SYS_MSG, 0, 0, "Invalid command.");
|
||||
}
|
||||
|
@ -56,4 +56,8 @@ void cmd_list_video_devices(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)
|
||||
void cmd_change_video_device(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
#endif /* VIDEO */
|
||||
|
||||
#ifdef PYTHON
|
||||
void cmd_run(WINDOW *, ToxWindow *, Tox *, int argc, char (*argv)[MAX_STR_SIZE]);
|
||||
#endif
|
||||
|
||||
#endif /* #define GLOBAL_COMMANDS_H */
|
||||
|
@ -69,8 +69,12 @@ static int max_groupchat_index = 0;
|
||||
extern struct user_settings *user_settings;
|
||||
extern struct Winthread Winthread;
|
||||
|
||||
#ifdef AUDIO
|
||||
#if defined(AUDIO) && defined(PYTHON)
|
||||
#define AC_NUM_GROUP_COMMANDS 25
|
||||
#elif AUDIO
|
||||
#define AC_NUM_GROUP_COMMANDS 24
|
||||
#elif PYTHON
|
||||
#define AC_NUM_GROUP_COMMANDS 21
|
||||
#else
|
||||
#define AC_NUM_GROUP_COMMANDS 20
|
||||
#endif /* AUDIO */
|
||||
@ -97,6 +101,12 @@ static const char group_cmd_list[AC_NUM_GROUP_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
{ "/requests" },
|
||||
{ "/status" },
|
||||
{ "/title" },
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
{ "/run" },
|
||||
|
||||
#endif /* PYTHON */
|
||||
};
|
||||
|
||||
int init_groupchat_win(ToxWindow *prompt, Tox *m, uint32_t groupnum, uint8_t type)
|
||||
@ -543,7 +553,15 @@ static void groupchat_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
TOX_MAX_NAME_LENGTH);
|
||||
} else if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0) {
|
||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||
} else {
|
||||
}
|
||||
|
||||
#ifdef PYTHON
|
||||
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0) {
|
||||
diff = dir_match(self, m, ctx->line, L"/run");
|
||||
}
|
||||
#endif
|
||||
|
||||
else {
|
||||
diff = complete_line(self, group_cmd_list, AC_NUM_GROUP_COMMANDS, MAX_CMDNAME_SIZE);
|
||||
}
|
||||
|
||||
|
65
src/help.c
65
src/help.c
@ -26,8 +26,13 @@
|
||||
#include "toxic.h"
|
||||
#include "help.h"
|
||||
#include "misc_tools.h"
|
||||
#include "api.h"
|
||||
|
||||
#ifdef PYTHON
|
||||
#define HELP_MENU_HEIGHT 10
|
||||
#else
|
||||
#define HELP_MENU_HEIGHT 9
|
||||
#endif /* PYTHON */
|
||||
#define HELP_MENU_WIDTH 26
|
||||
|
||||
void help_init_menu(ToxWindow *self)
|
||||
@ -95,6 +100,13 @@ static void help_draw_menu(ToxWindow *self)
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "oup commands\n");
|
||||
|
||||
#ifdef PYTHON
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, " p");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, "lugin commands\n");
|
||||
#endif /* PYTHON */
|
||||
|
||||
wattron(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
wprintw(win, " f");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(BLUE));
|
||||
@ -185,6 +197,14 @@ static void help_draw_global(ToxWindow *self)
|
||||
wprintw(win, " /svdev <type> <id> : Set active video device\n");
|
||||
#endif /* VIDEO */
|
||||
|
||||
#ifdef PYTHON
|
||||
wattron(win, A_BOLD);
|
||||
wprintw(win, "\n Scripting:\n");
|
||||
wattroff(win, A_BOLD);
|
||||
|
||||
wprintw(win, " /run <path> : Load and run the script at path\n");
|
||||
#endif /* PYTHON */
|
||||
|
||||
help_draw_bottom_menu(win);
|
||||
|
||||
box(win, ACS_VLINE, ACS_HLINE);
|
||||
@ -278,6 +298,26 @@ static void help_draw_group(ToxWindow *self)
|
||||
wrefresh(win);
|
||||
}
|
||||
|
||||
#ifdef PYTHON
|
||||
static void help_draw_plugin(ToxWindow *self)
|
||||
{
|
||||
WINDOW *win = self->help->win;
|
||||
|
||||
wmove(win, 1, 1);
|
||||
|
||||
wattron(win, A_BOLD | COLOR_PAIR(RED));
|
||||
wprintw(win, "Plugin commands:\n");
|
||||
wattroff(win, A_BOLD | COLOR_PAIR(RED));
|
||||
|
||||
draw_handler_help(win);
|
||||
|
||||
help_draw_bottom_menu(win);
|
||||
|
||||
box(win, ACS_VLINE, ACS_HLINE);
|
||||
wrefresh(win);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void help_draw_contacts(ToxWindow *self)
|
||||
{
|
||||
WINDOW *win = self->help->win;
|
||||
@ -302,6 +342,7 @@ static void help_draw_contacts(ToxWindow *self)
|
||||
|
||||
void help_onKey(ToxWindow *self, wint_t key)
|
||||
{
|
||||
int height;
|
||||
switch (key) {
|
||||
case 'x':
|
||||
case T_KEY_ESC:
|
||||
@ -320,13 +361,16 @@ void help_onKey(ToxWindow *self, wint_t key)
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
height = 22;
|
||||
#ifdef VIDEO
|
||||
help_init_window(self, 30, 80);
|
||||
height += 8;
|
||||
#elif AUDIO
|
||||
help_init_window(self, 26, 80);
|
||||
#else
|
||||
help_init_window(self, 22, 80);
|
||||
height += 4;
|
||||
#endif
|
||||
#ifdef PYTHON
|
||||
height += 2;
|
||||
#endif
|
||||
help_init_window(self, height, 80);
|
||||
self->help->type = HELP_GLOBAL;
|
||||
break;
|
||||
|
||||
@ -335,6 +379,13 @@ void help_onKey(ToxWindow *self, wint_t key)
|
||||
self->help->type = HELP_GROUP;
|
||||
break;
|
||||
|
||||
#ifdef PYTHON
|
||||
case 'p':
|
||||
help_init_window(self, 4 + num_registered_handlers(), help_max_width());
|
||||
self->help->type = HELP_PLUGIN;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case 'f':
|
||||
help_init_window(self, 10, 80);
|
||||
self->help->type = HELP_CONTACTS;
|
||||
@ -380,5 +431,11 @@ void help_onDraw(ToxWindow *self)
|
||||
case HELP_GROUP:
|
||||
help_draw_group(self);
|
||||
break;
|
||||
|
||||
#ifdef PYTHON
|
||||
case HELP_PLUGIN:
|
||||
help_draw_plugin(self);
|
||||
break;
|
||||
#endif /* PYTHON */
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,9 @@ typedef enum {
|
||||
HELP_GROUP,
|
||||
HELP_KEYS,
|
||||
HELP_CONTACTS,
|
||||
#ifdef PYTHON
|
||||
HELP_PLUGIN,
|
||||
#endif
|
||||
} HELP_TYPES;
|
||||
|
||||
void help_onDraw(ToxWindow *self);
|
||||
|
20
src/prompt.c
20
src/prompt.c
@ -49,10 +49,16 @@ extern struct Winthread Winthread;
|
||||
|
||||
extern FriendsList Friends;
|
||||
FriendRequests FrndRequests;
|
||||
#ifdef VIDEO
|
||||
#if defined(PYTHON) && defined(VIDEO)
|
||||
#define AC_NUM_GLOB_COMMANDS 23
|
||||
#elif defined(PYTHON) && defined(AUDIO)
|
||||
#define AC_NUM_GLOB_COMMANDS 21
|
||||
#elif VIDEO
|
||||
#define AC_NUM_GLOB_COMMANDS 22
|
||||
#elif AUDIO
|
||||
#define AC_NUM_GLOB_COMMANDS 20
|
||||
#elif PYTHON
|
||||
#define AC_NUM_GLOB_COMMANDS 19
|
||||
#else
|
||||
#define AC_NUM_GLOB_COMMANDS 18
|
||||
#endif
|
||||
@ -92,6 +98,12 @@ static const char glob_cmd_list[AC_NUM_GLOB_COMMANDS][MAX_CMDNAME_SIZE] = {
|
||||
|
||||
#endif /* VIDEO */
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
{ "/run" },
|
||||
|
||||
#endif /* PYTHON */
|
||||
|
||||
};
|
||||
|
||||
void kill_prompt_window(ToxWindow *self)
|
||||
@ -214,6 +226,12 @@ static void prompt_onKey(ToxWindow *self, Tox *m, wint_t key, bool ltr)
|
||||
|
||||
if (wcsncmp(ctx->line, L"/avatar \"", wcslen(L"/avatar \"")) == 0)
|
||||
diff = dir_match(self, m, ctx->line, L"/avatar");
|
||||
|
||||
#ifdef PYTHON
|
||||
else if (wcsncmp(ctx->line, L"/run \"", wcslen(L"/run \"")) == 0)
|
||||
diff = dir_match(self, m, ctx->line, L"/run");
|
||||
#endif
|
||||
|
||||
else if (wcsncmp(ctx->line, L"/status ", wcslen(L"/status ")) == 0) {
|
||||
const char status_cmd_list[3][8] = {
|
||||
{"online"},
|
||||
|
345
src/python_api.c
Normal file
345
src/python_api.c
Normal file
@ -0,0 +1,345 @@
|
||||
/* python_api.c
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
#include "api.h"
|
||||
#include "execute.h"
|
||||
|
||||
extern Tox *user_tox;
|
||||
|
||||
static struct python_registered_func {
|
||||
char *name;
|
||||
char *help;
|
||||
PyObject *callback;
|
||||
struct python_registered_func *next;
|
||||
} python_commands = {0};
|
||||
|
||||
static PyObject *python_api_display(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *msg;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &msg))
|
||||
return NULL;
|
||||
|
||||
api_display(msg);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *python_api_get_nick(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *name;
|
||||
PyObject *ret;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
name = api_get_nick();
|
||||
|
||||
if (name == NULL)
|
||||
return NULL;
|
||||
|
||||
ret = Py_BuildValue("s", name);
|
||||
free(name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *python_api_get_status(PyObject *self, PyObject *args)
|
||||
{
|
||||
PyObject *ret;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
switch (api_get_status()) {
|
||||
case TOX_USER_STATUS_NONE:
|
||||
ret = Py_BuildValue("s", "online");
|
||||
break;
|
||||
|
||||
case TOX_USER_STATUS_AWAY:
|
||||
ret = Py_BuildValue("s", "away");
|
||||
break;
|
||||
|
||||
case TOX_USER_STATUS_BUSY:
|
||||
ret = Py_BuildValue("s", "busy");
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *python_api_get_status_message(PyObject *self, PyObject *args)
|
||||
{
|
||||
char *status;
|
||||
PyObject *ret;
|
||||
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
status = api_get_status_message();
|
||||
|
||||
if (status == NULL)
|
||||
return NULL;
|
||||
|
||||
ret = Py_BuildValue("s", status);
|
||||
free(status);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *python_api_get_all_friends(PyObject *self, PyObject *args)
|
||||
{
|
||||
size_t i, ii;
|
||||
FriendsList friends;
|
||||
PyObject *cur, *ret;
|
||||
char pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2 + 1];
|
||||
|
||||
if (!PyArg_ParseTuple(args, ""))
|
||||
return NULL;
|
||||
|
||||
friends = api_get_friendslist();
|
||||
ret = PyList_New(0);
|
||||
|
||||
for (i = 0; i < friends.num_friends; i++) {
|
||||
for (ii = 0; ii < TOX_PUBLIC_KEY_SIZE; ii++)
|
||||
snprintf(pubkey_buf + ii * 2, 3, "%02X", friends.list[i].pub_key[ii] & 0xff);
|
||||
|
||||
pubkey_buf[TOX_PUBLIC_KEY_SIZE * 2] = '\0';
|
||||
cur = Py_BuildValue("(s,s)", friends.list[i].name, pubkey_buf);
|
||||
PyList_Append(ret, cur);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static PyObject *python_api_send(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char *msg;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &msg))
|
||||
return NULL;
|
||||
|
||||
api_send(msg);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *python_api_execute(PyObject *self, PyObject *args)
|
||||
{
|
||||
int mode;
|
||||
const char *command;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "si", &command, &mode))
|
||||
return NULL;
|
||||
|
||||
api_execute(command, mode);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyObject *python_api_register(PyObject *self, PyObject *args)
|
||||
{
|
||||
struct python_registered_func *cur;
|
||||
size_t command_len, help_len;
|
||||
const char *command, *help;
|
||||
PyObject *callback;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "ssO:register_command", &command, &help, &callback))
|
||||
return NULL;
|
||||
|
||||
if (!PyCallable_Check(callback)) {
|
||||
PyErr_SetString(PyExc_TypeError, "Calback parameter must be callable");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (command[0] != '/') {
|
||||
PyErr_SetString(PyExc_TypeError, "Command must be prefixed with a '/'");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (cur = &python_commands; ; cur = cur->next) {
|
||||
if (cur->name != NULL && !strcmp(command, cur->name)) {
|
||||
Py_XDECREF(cur->callback);
|
||||
Py_XINCREF(callback);
|
||||
cur->callback = callback;
|
||||
break;
|
||||
}
|
||||
|
||||
if (cur->next == NULL) {
|
||||
Py_XINCREF(callback);
|
||||
cur->next = malloc(sizeof(struct python_registered_func));
|
||||
|
||||
if (cur->next == NULL)
|
||||
return PyErr_NoMemory();
|
||||
|
||||
command_len = strlen(command);
|
||||
cur->next->name = malloc(command_len + 1);
|
||||
|
||||
if (cur->next->name == NULL)
|
||||
return PyErr_NoMemory();
|
||||
|
||||
strncpy(cur->next->name, command, command_len + 1);
|
||||
help_len = strlen(help);
|
||||
cur->next->help = malloc(help_len + 1);
|
||||
|
||||
if (cur->next->help == NULL)
|
||||
return PyErr_NoMemory();
|
||||
|
||||
strncpy(cur->next->help, help, help_len + 1);
|
||||
cur->next->callback = callback;
|
||||
cur->next->next = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
static PyMethodDef ToxicApiMethods[] = {
|
||||
{"display", python_api_display, METH_VARARGS, "Display a message to the current prompt"},
|
||||
{"get_nick", python_api_get_nick, METH_VARARGS, "Return the user's current nickname"},
|
||||
{"get_status", python_api_get_status, METH_VARARGS, "Returns the user's current status"},
|
||||
{"get_status_message", python_api_get_status_message, METH_VARARGS, "Return the user's current status message"},
|
||||
{"get_all_friends", python_api_get_all_friends, METH_VARARGS, "Return all of the user's friends"},
|
||||
{"send", python_api_send, METH_VARARGS, "Send the message to the current user"},
|
||||
{"execute", python_api_execute, METH_VARARGS, "Execute a command like `/nick`"},
|
||||
{"register", python_api_register, METH_VARARGS, "Register a command like `/nick` to a Python function"},
|
||||
{NULL, NULL, 0, NULL},
|
||||
};
|
||||
|
||||
static struct PyModuleDef toxic_api_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"toxic_api",
|
||||
NULL,
|
||||
-1,
|
||||
ToxicApiMethods
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC PyInit_toxic_api(void)
|
||||
{
|
||||
PyObject *m = PyModule_Create(&toxic_api_module);
|
||||
PyObject *global_command_const = Py_BuildValue("i", GLOBAL_COMMAND_MODE);
|
||||
PyObject *chat_command_const = Py_BuildValue("i", CHAT_COMMAND_MODE);
|
||||
PyObject *groupchat_command_const = Py_BuildValue("i", GROUPCHAT_COMMAND_MODE);
|
||||
PyObject_SetAttrString(m, "GLOBAL_COMMAND", global_command_const);
|
||||
PyObject_SetAttrString(m, "CHAT_COMMAND", chat_command_const);
|
||||
PyObject_SetAttrString(m, "GROUPCHAT_COMMAND", groupchat_command_const);
|
||||
Py_DECREF(global_command_const);
|
||||
Py_DECREF(chat_command_const);
|
||||
Py_DECREF(groupchat_command_const);
|
||||
return m;
|
||||
}
|
||||
|
||||
void terminate_python(void)
|
||||
{
|
||||
struct python_registered_func *cur, *old;
|
||||
|
||||
if (python_commands.name != NULL)
|
||||
free(python_commands.name);
|
||||
|
||||
for (cur = python_commands.next; cur != NULL;) {
|
||||
old = cur;
|
||||
cur = cur->next;
|
||||
free(old->name);
|
||||
free(old);
|
||||
}
|
||||
|
||||
Py_Finalize();
|
||||
}
|
||||
|
||||
void init_python(Tox *m)
|
||||
{
|
||||
user_tox = m;
|
||||
PyImport_AppendInittab("toxic_api", PyInit_toxic_api);
|
||||
Py_Initialize();
|
||||
}
|
||||
|
||||
void run_python(FILE *fp, char *path)
|
||||
{
|
||||
PyRun_SimpleFile(fp, path);
|
||||
}
|
||||
|
||||
int do_python_command(int num_args, char (*args)[MAX_STR_SIZE])
|
||||
{
|
||||
int i;
|
||||
PyObject *callback_args, *args_strings;
|
||||
struct python_registered_func *cur;
|
||||
|
||||
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||
if (cur->name == NULL)
|
||||
continue;
|
||||
|
||||
if (!strcmp(args[0], cur->name)) {
|
||||
args_strings = PyList_New(0);
|
||||
|
||||
for (i = 1; i < num_args; i++)
|
||||
PyList_Append(args_strings, Py_BuildValue("s", args[i]));
|
||||
|
||||
callback_args = PyTuple_Pack(1, args_strings);
|
||||
|
||||
if (PyObject_CallObject(cur->callback, callback_args) == NULL)
|
||||
api_display("Exception raised in callback function");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int python_num_registered_handlers(void)
|
||||
{
|
||||
int n = 0;
|
||||
struct python_registered_func *cur;
|
||||
|
||||
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||
if (cur->name != NULL)
|
||||
n++;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int python_help_max_width(void)
|
||||
{
|
||||
size_t tmp;
|
||||
int max = 0;
|
||||
struct python_registered_func *cur;
|
||||
|
||||
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||
if (cur->name != NULL) {
|
||||
tmp = strlen(cur->help);
|
||||
max = tmp > max ? tmp : max;
|
||||
}
|
||||
}
|
||||
|
||||
max = max > 50 ? 50 : max;
|
||||
return 37 + max;
|
||||
}
|
||||
|
||||
void python_draw_handler_help(WINDOW *win)
|
||||
{
|
||||
struct python_registered_func *cur;
|
||||
|
||||
for (cur = &python_commands; cur != NULL; cur = cur->next) {
|
||||
if (cur->name != NULL)
|
||||
wprintw(win, " %-29s: %.50s\n", cur->name, cur->help);
|
||||
}
|
||||
}
|
37
src/python_api.h
Normal file
37
src/python_api.h
Normal file
@ -0,0 +1,37 @@
|
||||
/* python_api.h
|
||||
*
|
||||
*
|
||||
* Copyright (C) 2017 Jakob Kreuze <jakob@memeware.net>
|
||||
*
|
||||
* This file is part of Toxic.
|
||||
*
|
||||
* Toxic is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Toxic 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Toxic. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PYTHON_API_H
|
||||
#define PYTHON_API_H
|
||||
|
||||
#include <Python.h>
|
||||
|
||||
PyMODINIT_FUNC PyInit_toxic_api(void);
|
||||
void terminate_python(void);
|
||||
void init_python(Tox *m);
|
||||
void run_python(FILE *fp, char *path);
|
||||
int do_python_command(int num_args, char (*args)[MAX_STR_SIZE]);
|
||||
int python_num_registered_handlers(void);
|
||||
int python_help_max_width(void);
|
||||
void python_draw_handler_help(WINDOW *win);
|
||||
|
||||
#endif /* #define PYTHON_API_H */
|
@ -179,12 +179,14 @@ static const struct tox_strings {
|
||||
const char *download_path;
|
||||
const char *chatlogs_path;
|
||||
const char *avatar_path;
|
||||
const char *autorun_path;
|
||||
const char *password_eval;
|
||||
} tox_strings = {
|
||||
"tox",
|
||||
"download_path",
|
||||
"chatlogs_path",
|
||||
"avatar_path",
|
||||
"autorun_path",
|
||||
"password_eval",
|
||||
};
|
||||
|
||||
@ -193,6 +195,7 @@ static void tox_defaults(struct user_settings *settings)
|
||||
strcpy(settings->download_path, "");
|
||||
strcpy(settings->chatlogs_path, "");
|
||||
strcpy(settings->avatar_path, "");
|
||||
strcpy(settings->autorun_path, "");
|
||||
strcpy(settings->password_eval, "");
|
||||
}
|
||||
|
||||
@ -418,6 +421,20 @@ int settings_load(struct user_settings *s, const char *patharg)
|
||||
s->avatar_path[0] = '\0';
|
||||
}
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
if ( config_setting_lookup_string(setting, tox_strings.autorun_path, &str) ) {
|
||||
snprintf(s->autorun_path, sizeof(s->autorun_path), "%s", str);
|
||||
int len = strlen(str);
|
||||
|
||||
if (len >= sizeof(s->autorun_path) - 2)
|
||||
s->autorun_path[0] = '\0';
|
||||
else if (s->autorun_path[len - 1] != '/')
|
||||
strcat(&s->autorun_path[len - 1], "/");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if ( config_setting_lookup_string(setting, tox_strings.password_eval, &str) ) {
|
||||
snprintf(s->password_eval, sizeof(s->password_eval), "%s", str);
|
||||
int len = strlen(str);
|
||||
|
@ -63,6 +63,7 @@ struct user_settings {
|
||||
char download_path[PATH_MAX];
|
||||
char chatlogs_path[PATH_MAX];
|
||||
char avatar_path[PATH_MAX];
|
||||
char autorun_path[PATH_MAX];
|
||||
char password_eval[PASSWORD_EVAL_MAX];
|
||||
|
||||
int key_next_tab;
|
||||
|
16
src/toxic.c
16
src/toxic.c
@ -75,6 +75,11 @@
|
||||
ToxAV *av;
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef PYTHON
|
||||
#include "api.h"
|
||||
#include "python_api.h"
|
||||
#endif
|
||||
|
||||
#ifndef PACKAGE_DATADIR
|
||||
#define PACKAGE_DATADIR "."
|
||||
#endif
|
||||
@ -169,6 +174,10 @@ void exit_toxic_success(Tox *m)
|
||||
terminate_audio();
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef PYTHON
|
||||
terminate_python();
|
||||
#endif /* PYTHON */
|
||||
|
||||
free_global_data();
|
||||
tox_kill(m);
|
||||
endwin();
|
||||
@ -1218,6 +1227,13 @@ int main(int argc, char **argv)
|
||||
|
||||
#endif /* AUDIO */
|
||||
|
||||
#ifdef PYTHON
|
||||
|
||||
init_python(m);
|
||||
invoke_autoruns(prompt->chatwin->history, prompt);
|
||||
|
||||
#endif /* PYTHON */
|
||||
|
||||
init_notify(60, 3000);
|
||||
|
||||
/* screen/tmux auto-away timer */
|
||||
|
@ -584,6 +584,12 @@ ToxWindow *get_window_ptr(int i)
|
||||
return toxwin;
|
||||
}
|
||||
|
||||
/* returns a pointer to the currently open ToxWindow. */
|
||||
ToxWindow *get_active_window(void)
|
||||
{
|
||||
return active_window;
|
||||
}
|
||||
|
||||
void force_refresh(WINDOW *w)
|
||||
{
|
||||
wclear(w);
|
||||
|
@ -259,6 +259,7 @@ void kill_all_windows(Tox *m); /* should only be called on shutdown */
|
||||
void on_window_resize(void);
|
||||
void force_refresh(WINDOW *w);
|
||||
ToxWindow *get_window_ptr(int i);
|
||||
ToxWindow *get_active_window(void);
|
||||
|
||||
/* refresh inactive windows to prevent scrolling bugs.
|
||||
call at least once per second */
|
||||
|
Loading…
Reference in New Issue
Block a user