448 lines
11 KiB
C
448 lines
11 KiB
C
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#ifdef USE_LUA
|
|
#include "lua-tg.h"
|
|
|
|
#include "include.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
|
|
#include <lua.h>
|
|
#include <lualib.h>
|
|
#include <lauxlib.h>
|
|
lua_State *luaState;
|
|
|
|
#include "structures.h"
|
|
#include "interface.h"
|
|
#include "constants.h"
|
|
#include "tools.h"
|
|
#include "queries.h"
|
|
|
|
extern int verbosity;
|
|
|
|
static int have_file;
|
|
|
|
#define my_lua_checkstack(L,x) assert (lua_checkstack (L, x))
|
|
void push_user (peer_t *P UU);
|
|
void push_peer (peer_id_t id, peer_t *P);
|
|
|
|
void lua_add_string_field (const char *name, const char *value) {
|
|
assert (name && strlen (name));
|
|
if (!value || !strlen (value)) { return; }
|
|
my_lua_checkstack (luaState, 3);
|
|
lua_pushstring (luaState, name);
|
|
lua_pushstring (luaState, value);
|
|
lua_settable (luaState, -3);
|
|
}
|
|
|
|
void lua_add_num_field (const char *name, double value) {
|
|
assert (name && strlen (name));
|
|
my_lua_checkstack (luaState, 3);
|
|
lua_pushstring (luaState, name);
|
|
lua_pushnumber (luaState, value);
|
|
lua_settable (luaState, -3);
|
|
}
|
|
|
|
void push_peer_type (int x) {
|
|
switch (x) {
|
|
case PEER_USER:
|
|
lua_pushstring (luaState, "user");
|
|
break;
|
|
case PEER_CHAT:
|
|
lua_pushstring (luaState, "chat");
|
|
break;
|
|
case PEER_ENCR_CHAT:
|
|
lua_pushstring (luaState, "encr_chat");
|
|
break;
|
|
default:
|
|
assert (0);
|
|
}
|
|
}
|
|
|
|
void push_user (peer_t *P UU) {
|
|
my_lua_checkstack (luaState, 4);
|
|
lua_add_string_field ("first_name", P->user.first_name);
|
|
lua_add_string_field ("last_name", P->user.last_name);
|
|
lua_add_string_field ("real_first_name", P->user.real_first_name);
|
|
lua_add_string_field ("real_last_name", P->user.real_last_name);
|
|
lua_add_string_field ("phone", P->user.phone);
|
|
}
|
|
|
|
void push_chat (peer_t *P) {
|
|
my_lua_checkstack (luaState, 4);
|
|
assert (P->chat.title);
|
|
lua_add_string_field ("title", P->chat.title);
|
|
lua_add_num_field ("members_num", P->chat.users_num);
|
|
}
|
|
|
|
void push_encr_chat (peer_t *P) {
|
|
my_lua_checkstack (luaState, 4);
|
|
lua_pushstring (luaState, "user");
|
|
push_peer (MK_USER (P->encr_chat.user_id), user_chat_get (MK_USER (P->encr_chat.user_id)));
|
|
lua_settable (luaState, -3);
|
|
}
|
|
|
|
void push_peer (peer_id_t id, peer_t *P) {
|
|
lua_newtable (luaState);
|
|
|
|
lua_add_num_field ("id", get_peer_id (id));
|
|
lua_pushstring (luaState, "type");
|
|
push_peer_type (get_peer_type (id));
|
|
lua_settable (luaState, -3);
|
|
|
|
|
|
if (!P || !(P->flags & FLAG_CREATED)) {
|
|
lua_pushstring (luaState, "print_name");
|
|
static char s[100];
|
|
switch (get_peer_type (id)) {
|
|
case PEER_USER:
|
|
sprintf (s, "user#%d", get_peer_id (id));
|
|
break;
|
|
case PEER_CHAT:
|
|
sprintf (s, "chat#%d", get_peer_id (id));
|
|
break;
|
|
case PEER_ENCR_CHAT:
|
|
sprintf (s, "encr_chat#%d", get_peer_id (id));
|
|
break;
|
|
default:
|
|
assert (0);
|
|
}
|
|
lua_pushstring (luaState, s);
|
|
lua_settable (luaState, -3); // flags
|
|
|
|
return;
|
|
}
|
|
|
|
lua_add_string_field ("print_name", P->print_name);
|
|
lua_add_num_field ("flags", P->flags);
|
|
|
|
switch (get_peer_type (id)) {
|
|
case PEER_USER:
|
|
push_user (P);
|
|
break;
|
|
case PEER_CHAT:
|
|
push_chat (P);
|
|
break;
|
|
case PEER_ENCR_CHAT:
|
|
push_encr_chat (P);
|
|
break;
|
|
default:
|
|
assert (0);
|
|
}
|
|
}
|
|
|
|
void push_media (struct message_media *M) {
|
|
my_lua_checkstack (luaState, 4);
|
|
|
|
switch (M->type) {
|
|
case CODE_message_media_photo:
|
|
case CODE_decrypted_message_media_photo:
|
|
lua_pushstring (luaState, "photo");
|
|
break;
|
|
case CODE_message_media_video:
|
|
case CODE_decrypted_message_media_video:
|
|
lua_pushstring (luaState, "video");
|
|
break;
|
|
case CODE_message_media_audio:
|
|
case CODE_decrypted_message_media_audio:
|
|
lua_pushstring (luaState, "audio");
|
|
break;
|
|
case CODE_message_media_document:
|
|
case CODE_decrypted_message_media_document:
|
|
lua_pushstring (luaState, "document");
|
|
break;
|
|
case CODE_message_media_unsupported:
|
|
lua_pushstring (luaState, "unsupported");
|
|
break;
|
|
case CODE_message_media_geo:
|
|
lua_newtable (luaState);
|
|
lua_add_num_field ("longitude", M->geo.longitude);
|
|
lua_add_num_field ("latitude", M->geo.latitude);
|
|
break;
|
|
case CODE_message_media_contact:
|
|
case CODE_decrypted_message_media_contact:
|
|
lua_newtable (luaState);
|
|
lua_add_string_field ("phone", M->phone);
|
|
lua_add_string_field ("first_name", M->first_name);
|
|
lua_add_string_field ("last_name", M->last_name);
|
|
lua_add_num_field ("user_id", M->user_id);
|
|
break;
|
|
default:
|
|
lua_pushstring (luaState, "???");
|
|
}
|
|
}
|
|
|
|
void push_message (struct message *M) {
|
|
assert (M);
|
|
my_lua_checkstack (luaState, 10);
|
|
lua_newtable (luaState);
|
|
|
|
static char s[30];
|
|
tsnprintf (s, 30, "%lld", M->id);
|
|
lua_add_string_field ("id", s);
|
|
lua_add_num_field ("flags", M->flags);
|
|
|
|
if (get_peer_type (M->fwd_from_id)) {
|
|
lua_pushstring (luaState, "fwd_from");
|
|
push_peer (M->fwd_from_id, user_chat_get (M->fwd_from_id));
|
|
lua_settable (luaState, -3); // fwd_from
|
|
|
|
lua_add_num_field ("fwd_date", M->fwd_date);
|
|
}
|
|
|
|
lua_pushstring (luaState, "from");
|
|
push_peer (M->from_id, user_chat_get (M->from_id));
|
|
lua_settable (luaState, -3);
|
|
|
|
lua_pushstring (luaState, "to");
|
|
push_peer (M->to_id, user_chat_get (M->to_id));
|
|
lua_settable (luaState, -3);
|
|
|
|
lua_pushstring (luaState, "out");
|
|
lua_pushboolean (luaState, M->out);
|
|
lua_settable (luaState, -3);
|
|
|
|
lua_pushstring (luaState, "unread");
|
|
lua_pushboolean (luaState, M->unread);
|
|
lua_settable (luaState, -3);
|
|
|
|
lua_pushstring (luaState, "date");
|
|
lua_pushnumber (luaState, M->date);
|
|
lua_settable (luaState, -3);
|
|
|
|
lua_pushstring (luaState, "service");
|
|
lua_pushboolean (luaState, M->service);
|
|
lua_settable (luaState, -3);
|
|
|
|
if (!M->service) {
|
|
if (M->message_len && M->message) {
|
|
lua_pushstring (luaState, "text");
|
|
lua_pushlstring (luaState, M->message, M->message_len);
|
|
lua_settable (luaState, -3);
|
|
}
|
|
if (M->media.type && M->media.type != CODE_message_media_empty && M->media.type != CODE_decrypted_message_media_empty) {
|
|
lua_pushstring (luaState, "media");
|
|
push_media (&M->media);
|
|
lua_settable (luaState, -3);
|
|
}
|
|
}
|
|
}
|
|
|
|
void lua_binlog_end (void) {
|
|
if (!have_file) { return; }
|
|
lua_settop (luaState, 0);
|
|
//lua_checkstack (luaState, 20);
|
|
my_lua_checkstack (luaState, 20);
|
|
lua_getglobal (luaState, "on_binlog_replay_end");
|
|
assert (lua_gettop (luaState) == 1);
|
|
|
|
int r = lua_pcall (luaState, 0, 0, 0);
|
|
if (r) {
|
|
logprintf ("lua: %s\n", lua_tostring (luaState, -1));
|
|
}
|
|
}
|
|
|
|
void lua_diff_end (void) {
|
|
if (!have_file) { return; }
|
|
lua_settop (luaState, 0);
|
|
//lua_checkstack (luaState, 20);
|
|
my_lua_checkstack (luaState, 20);
|
|
lua_getglobal (luaState, "on_get_difference_end");
|
|
assert (lua_gettop (luaState) == 1);
|
|
|
|
int r = lua_pcall (luaState, 0, 0, 0);
|
|
if (r) {
|
|
logprintf ("lua: %s\n", lua_tostring (luaState, -1));
|
|
}
|
|
}
|
|
|
|
void lua_our_id (int id) {
|
|
if (!have_file) { return; }
|
|
lua_settop (luaState, 0);
|
|
//lua_checkstack (luaState, 20);
|
|
my_lua_checkstack (luaState, 20);
|
|
lua_getglobal (luaState, "on_our_id");
|
|
lua_pushnumber (luaState, id);
|
|
assert (lua_gettop (luaState) == 2);
|
|
|
|
int r = lua_pcall (luaState, 1, 0, 0);
|
|
if (r) {
|
|
logprintf ("lua: %s\n", lua_tostring (luaState, -1));
|
|
}
|
|
}
|
|
|
|
void lua_new_msg (struct message *M UU) {
|
|
if (!have_file) { return; }
|
|
lua_settop (luaState, 0);
|
|
//lua_checkstack (luaState, 20);
|
|
my_lua_checkstack (luaState, 20);
|
|
lua_getglobal (luaState, "on_msg_receive");
|
|
push_message (M);
|
|
assert (lua_gettop (luaState) == 2);
|
|
|
|
int r = lua_pcall (luaState, 1, 0, 0);
|
|
if (r) {
|
|
logprintf ("lua: %s\n", lua_tostring (luaState, -1));
|
|
}
|
|
}
|
|
|
|
void lua_secret_chat_created (struct secret_chat *C) {
|
|
if (!have_file) { return; }
|
|
lua_settop (luaState, 0);
|
|
//lua_checkstack (luaState, 20);
|
|
my_lua_checkstack (luaState, 20);
|
|
lua_getglobal (luaState, "on_secret_chat_created");
|
|
push_peer (C->id, (void *)C);
|
|
assert (lua_gettop (luaState) == 2);
|
|
|
|
int r = lua_pcall (luaState, 1, 0, 0);
|
|
if (r) {
|
|
logprintf ("lua: %s\n", lua_tostring (luaState, -1));
|
|
}
|
|
}
|
|
|
|
void lua_user_update (struct user *U) {
|
|
if (!have_file) { return; }
|
|
lua_settop (luaState, 0);
|
|
//lua_checkstack (luaState, 20);
|
|
my_lua_checkstack (luaState, 20);
|
|
lua_getglobal (luaState, "on_user_update");
|
|
push_peer (U->id, (void *)U);
|
|
assert (lua_gettop (luaState) == 2);
|
|
|
|
int r = lua_pcall (luaState, 1, 0, 0);
|
|
if (r) {
|
|
logprintf ("lua: %s\n", lua_tostring (luaState, -1));
|
|
}
|
|
}
|
|
|
|
void lua_chat_update (struct chat *C) {
|
|
if (!have_file) { return; }
|
|
lua_settop (luaState, 0);
|
|
//lua_checkstack (luaState, 20);
|
|
my_lua_checkstack (luaState, 20);
|
|
lua_getglobal (luaState, "on_chat_update");
|
|
push_peer (C->id, (void *)C);
|
|
assert (lua_gettop (luaState) == 2);
|
|
|
|
int r = lua_pcall (luaState, 1, 0, 0);
|
|
if (r) {
|
|
logprintf ("lua: %s\n", lua_tostring (luaState, -1));
|
|
}
|
|
}
|
|
|
|
extern peer_t *Peers[];
|
|
extern int peer_num;
|
|
|
|
#define MAX_LUA_COMMANDS 1000
|
|
void *lua_ptr[MAX_LUA_COMMANDS];
|
|
static int pos;
|
|
|
|
static peer_t *get_peer (const char *s) {
|
|
int index = 0;
|
|
while (index < peer_num && Peers[index]->print_name && strcmp (Peers[index]->print_name, s)) {
|
|
index ++;
|
|
}
|
|
return index == peer_num ? 0 : Peers[index];
|
|
}
|
|
|
|
void lua_do_all (void) {
|
|
int p = 0;
|
|
while (p < pos) {
|
|
int l = (long)lua_ptr[p ++];
|
|
assert (p + l + 1 <= pos);
|
|
int f = (long)lua_ptr[p ++];
|
|
switch (f) {
|
|
case 0:
|
|
do_send_message (((peer_t *)lua_ptr[p])->id, lua_ptr[p + 1], strlen (lua_ptr[p + 1]));
|
|
tfree_str (lua_ptr[p + 1]);
|
|
p += 2;
|
|
break;
|
|
case 1:
|
|
do_forward_message (((peer_t *)lua_ptr[p])->id, (long)lua_ptr[p + 1]);
|
|
p += 2;
|
|
break;
|
|
default:
|
|
assert (0);
|
|
}
|
|
}
|
|
pos = 0;
|
|
}
|
|
|
|
|
|
static int send_msg_from_lua (lua_State *L) {
|
|
if (MAX_LUA_COMMANDS - pos < 4) {
|
|
lua_pushboolean (L, 0);
|
|
return 1;
|
|
}
|
|
int n = lua_gettop (L);
|
|
if (n != 2) {
|
|
lua_pushboolean (L, 0);
|
|
return 1;
|
|
}
|
|
const char *s = lua_tostring (L, -2);
|
|
const char *msg = lua_tostring (L, -1);
|
|
|
|
peer_t *P = get_peer (s);
|
|
if (!P) {
|
|
lua_pushboolean (L, 0);
|
|
return 1;
|
|
}
|
|
|
|
lua_ptr[pos ++] = (void *)2l;
|
|
lua_ptr[pos ++] = (void *)0l;
|
|
lua_ptr[pos ++] = P;
|
|
lua_ptr[pos ++] = tstrdup (msg);
|
|
logprintf ("msg = %s\n", msg);
|
|
|
|
lua_pushboolean (L, 1);
|
|
return 1;
|
|
}
|
|
|
|
static int fwd_msg_from_lua (lua_State *L) {
|
|
if (MAX_LUA_COMMANDS - pos < 4) {
|
|
lua_pushboolean (L, 0);
|
|
return 1;
|
|
}
|
|
int n = lua_gettop (L);
|
|
if (n != 2) {
|
|
lua_pushboolean (L, 0);
|
|
return 1;
|
|
}
|
|
const char *s = lua_tostring (L, -2);
|
|
long long num = atoll (lua_tostring (L, -1));
|
|
peer_t *P = get_peer (s);
|
|
if (!P) {
|
|
lua_pushboolean (L, 0);
|
|
return 1;
|
|
}
|
|
|
|
lua_ptr[pos ++] = (void *)2l;
|
|
lua_ptr[pos ++] = (void *)1l;
|
|
lua_ptr[pos ++] = P;
|
|
lua_ptr[pos ++] = (void *)(long)num;
|
|
lua_pushboolean (L, 1);
|
|
return 1;
|
|
}
|
|
|
|
void lua_init (const char *file) {
|
|
if (!file) { return; }
|
|
have_file = 1;
|
|
luaState = luaL_newstate ();
|
|
luaL_openlibs (luaState);
|
|
|
|
lua_register (luaState, "send_msg", send_msg_from_lua);
|
|
lua_register (luaState, "fwd_msg", fwd_msg_from_lua);
|
|
|
|
int ret = luaL_dofile (luaState, file);
|
|
if (ret) {
|
|
logprintf ("lua: %s\n", lua_tostring (luaState, -1));
|
|
exit (1);
|
|
}
|
|
}
|
|
|
|
#endif
|