Created
March 18, 2016 17:50
-
-
Save sepi/13d1da27d5599ba105b8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* Libotr bindings for emacs | |
Copyright 2016 Free Software Foundation, Inc. | |
This file is part of GNU Emacs. | |
GNU Emacs 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. | |
GNU Emacs 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 GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |
#include <stdbool.h> | |
#include <emacs-module.h> | |
#include <libotr/proto.h> | |
#include <libotr/privkey.h> | |
#include <libotr/message.h> | |
#define STR_SIZE_MAX 2048 | |
#define EMACS_FUNCTION(name) \ | |
static emacs_value \ | |
F##name (emacs_env *env, int nargs, emacs_value args[], void *data) | |
int plugin_is_GPL_compatible; | |
static emacs_value t; | |
static emacs_value nil; | |
/* Bind NAME to FUN. */ | |
static void | |
bind_function (emacs_env *env, const char *name, emacs_value Sfun) | |
{ | |
emacs_value Qfset = env->intern (env, "fset"); | |
emacs_value Qsym = env->intern (env, name); | |
emacs_value args[] = { Qsym, Sfun }; | |
env->funcall (env, Qfset, 2, args); | |
} | |
/* Provide FEATURE to Emacs. */ | |
static void | |
provide (emacs_env *env, const char *feature) | |
{ | |
emacs_value Qfeat = env->intern (env, feature); | |
emacs_value Qprovide = env->intern (env, "provide"); | |
emacs_value args[] = { Qfeat }; | |
env->funcall (env, Qprovide, 1, args); | |
} | |
void | |
otr_user_state_finalizer(void *data) | |
{ | |
OtrlUserState *user_state = (OtrlUserState*)data; | |
if (user_state != NULL) | |
{ | |
otrl_userstate_free(*user_state); | |
} | |
} | |
void | |
otr_ui_ops_finalizer(void *data) | |
{ | |
OtrlMessageAppOps *ui_ops = data; | |
if (ui_ops != NULL) | |
{ | |
free(ui_ops); | |
} | |
} | |
/* TODO: remember to call relevant function with env as opdata!!! */ | |
char ui_op_policy_name[STR_SIZE_MAX] = ""; | |
OtrlPolicy | |
ui_op_policy(void *opdata, ConnContext *context) | |
{ | |
emacs_env *env = (emacs_env *)opdata; | |
emacs_value function_name = env->intern (env, ui_op_policy_name); | |
emacs_value context_ptr = env->make_user_ptr(env, NULL, (void *)context); | |
emacs_value lisp_policy = env->funcall (env, function_name, 1, &context_ptr); | |
OtrlPolicy policy = env->extract_integer (env, lisp_policy); | |
return policy; | |
} | |
char ui_op_create_privkey_name[STR_SIZE_MAX] = ""; | |
void | |
ui_op_create_privkey(void *opdata, const char *accountname, const char *protocol) | |
{ | |
emacs_env *env = (emacs_env *)opdata; | |
emacs_value function_name = env->intern (env, ui_op_create_privkey_name); | |
emacs_value lisp_accountname = env->make_string (env, accountname, strlen(accountname)); | |
emacs_value lisp_protocol = env->make_string (env, protocol, strlen(protocol)); | |
emacs_value args[] = {lisp_accountname, lisp_protocol}; | |
env->funcall (env, function_name, 2, args); | |
} | |
char ui_op_is_logged_in_name[STR_SIZE_MAX] = ""; | |
int | |
ui_op_is_logged_in(void *opdata, const char *accountname, const char *protocol, | |
const char *recipient, const char *message) | |
{ | |
emacs_env *env = (emacs_env *)opdata; | |
emacs_value function_name = env->intern (env, ui_op_is_logged_in_name); | |
emacs_value lisp_accountname = env->make_string (env, accountname, strlen(accountname)); | |
emacs_value lisp_protocol = env->make_string (env, protocol, strlen(protocol)); | |
emacs_value lisp_recipient = env->make_string (env, recipient, strlen(recipient)); | |
emacs_value lisp_message = env->make_string (env, message, strlen(message)); | |
emacs_value args[] = {lisp_accountname, lisp_protocol, lisp_recipient, lisp_message}; | |
emacs_value ret = env->funcall (env, function_name , 4, args); | |
return env->extract_integer (env, ret); | |
} | |
EMACS_FUNCTION(otr_uiops_create) | |
{ | |
OtrlMessageAppOps *ui_ops = (OtrlMessageAppOps *) malloc (sizeof (OtrlMessageAppOps)); | |
/* TODO: Handle allocation error (although not relevant on linux afaik) */ | |
ui_ops->policy = NULL; | |
ui_ops->create_privkey = NULL; | |
ui_ops->is_logged_in = NULL; | |
ui_ops->inject_message = NULL; | |
ui_ops->update_context_list = NULL; | |
ui_ops->new_fingerprint = NULL; | |
ui_ops->write_fingerprints = NULL; | |
ui_ops->gone_secure = NULL; | |
ui_ops->gone_insecure = NULL; | |
ui_ops->still_secure = NULL; | |
ui_ops->max_message_size = NULL; | |
ui_ops->account_name = NULL; | |
ui_ops->account_name_free = NULL; | |
ui_ops->received_symkey = NULL; | |
ui_ops->otr_error_message = NULL; | |
ui_ops->otr_error_message_free = NULL; | |
ui_ops->resent_msg_prefix = NULL; | |
ui_ops->resent_msg_prefix_free = NULL; | |
ui_ops->handle_smp_event = NULL; | |
ui_ops->handle_msg_event = NULL; | |
ui_ops->create_instag = NULL; | |
ui_ops->convert_msg = NULL; | |
ui_ops->convert_free = NULL; | |
ui_ops->timer_control = NULL; | |
emacs_value ui_ops_ptr = env->make_user_ptr(env, | |
otr_ui_ops_finalizer, | |
(void *)ui_ops); | |
return ui_ops_ptr; | |
} | |
/* takes UI-ops object, callback name as a string and an emacs function and | |
assigns the emacs function to the correct slot of the UI-ops object */ | |
EMACS_FUNCTION(otr_uiops_set_callback) | |
{ | |
OtrlMessageAppOps *ui_ops = env->get_user_ptr (env, args[0]); | |
char callback_name[STR_SIZE_MAX]; /* The name of the callback as defined in the lib */ | |
size_t bytes_copied = STR_SIZE_MAX; | |
bool copied = env->copy_string_contents (env, args[1], | |
callback_name, | |
&bytes_copied); | |
/* TODO */ | |
/* if (!copied) */ | |
/* { */ | |
/* } */ | |
char callback_symbol_name[STR_SIZE_MAX]; /* The name of the lisp | |
function to be called as | |
a string */ | |
bytes_copied = STR_SIZE_MAX; | |
copied = env->copy_string_contents (env, args[2], | |
callback_symbol_name, | |
&bytes_copied); | |
#define SET_CB(name) \ | |
if (strncmp(#name, callback_name, STR_SIZE_MAX)) { \ | |
strncpy(ui_op_ ## name ## _name, callback_symbol_name, STR_SIZE_MAX); \ | |
ui_ops->name = ui_op_ ## name; \ | |
return t; \ | |
} | |
if (copied) | |
{ | |
SET_CB(policy); | |
SET_CB(create_privkey); | |
SET_CB(is_logged_in); | |
} | |
else | |
{ | |
return nil; | |
} | |
} | |
EMACS_FUNCTION(otr_userstate_create) | |
{ | |
OtrlUserState user_state = otrl_userstate_create(); | |
emacs_value user_state_ptr = env->make_user_ptr(env, | |
otr_user_state_finalizer, | |
(void*)&user_state); | |
return user_state_ptr; | |
} | |
EMACS_FUNCTION(otr_privkey_read) | |
{ | |
OtrlUserState *userstate = env->get_user_ptr (env, args[0]); | |
char privkey_filename[STR_SIZE_MAX]; | |
size_t bytes_copied = STR_SIZE_MAX; | |
bool copied = env->copy_string_contents (env, args[1], | |
privkey_filename, | |
&bytes_copied); | |
if (copied) | |
{ | |
gcry_error_t err = otrl_privkey_read (*userstate, privkey_filename); /* TODO: handle error */ | |
return t; | |
} | |
error_exit: | |
return nil; /* TODO: handle error */ | |
} | |
EMACS_FUNCTION(otr_instag_read) | |
{ | |
OtrlUserState *userstate = env->get_user_ptr (env, args[0]); | |
char instag_filename[STR_SIZE_MAX]; | |
size_t bytes_copied = STR_SIZE_MAX; | |
bool copied = env->copy_string_contents (env, args[1], | |
instag_filename, | |
&bytes_copied); | |
if (copied) | |
{ | |
gcry_error_t err = otrl_instag_read (*userstate, instag_filename); /* TODO: handle error */ | |
return t; | |
} | |
error_exit: | |
return nil; /* TODO: handle error */ | |
} | |
EMACS_FUNCTION(otr_privkey_read_fingerprints) | |
{ | |
OtrlUserState *userstate = env->get_user_ptr (env, args[0]); | |
char fingerprint_filename[STR_SIZE_MAX]; | |
size_t bytes_copied = STR_SIZE_MAX; | |
bool copied = env->copy_string_contents (env, args[1], | |
fingerprint_filename, | |
&bytes_copied); | |
if (copied) | |
{ | |
gcry_error_t err = otrl_privkey_read_fingerprints (*userstate, fingerprint_filename, | |
NULL, NULL); /* TODO: handle error */ | |
return t; | |
} | |
error_exit: | |
return nil; /* TODO: handle error */ | |
} | |
int | |
emacs_module_init (struct emacs_runtime *ert) | |
{ | |
emacs_env *env = ert->get_environment (ert); | |
/* Useful symbols */ | |
t = env->intern (env, "t"); | |
nil = env->intern (env, "nil"); | |
/* Create function bindings */ | |
bind_function (env, "otr-uiops-create", | |
env->make_function (env, 0, 0, Fotr_uiops_create, "doc", NULL)); | |
bind_function (env, "otr-userstate-create", | |
env->make_function (env, 0, 0, Fotr_userstate_create, "doc", NULL)); | |
bind_function (env, "otr-privkey-read", | |
env->make_function (env, 2, 2, Fotr_privkey_read, "doc", NULL)); | |
bind_function (env, "otr-instag-read", | |
env->make_function (env, 2, 2, Fotr_instag_read, "doc", NULL)); | |
bind_function (env, "otr-privkey-read-fingerprints", | |
env->make_function (env, 2, 2, Fotr_privkey_read_fingerprints, "doc", NULL)); | |
provide (env, "otr"); | |
OTRL_INIT; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment