Slightly working version
This commit is contained in:
commit
8f69d8d11d
17 changed files with 2531 additions and 0 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
*.o
|
||||
*.so
|
||||
tg/
|
120
Makefile
Normal file
120
Makefile
Normal file
|
@ -0,0 +1,120 @@
|
|||
#
|
||||
# Telegram Flags
|
||||
#
|
||||
|
||||
srcdir=.
|
||||
CFLAGS=-g -Wall -Wextra -Werror -Wno-unused-parameter
|
||||
LDFLAGS=-L/usr/local/lib
|
||||
CPPFLAGS=-I/usr/local/include -Itg
|
||||
DEFS=
|
||||
COMPILE_FLAGS=${CFLAGS} ${CPPFLAGS} ${DEFS} -Wall -Wextra -Wno-deprecated-declarations -fno-strict-aliasing -fno-omit-frame-pointer -ggdb
|
||||
EXTRA_LIBS=-lcrypto -lz -lm
|
||||
LOCAL_LDFLAGS=-rdynamic -ggdb ${EXTRA_LIBS}
|
||||
LINK_FLAGS=${LDFLAGS} ${LOCAL_LDFLAGS}
|
||||
|
||||
INCLUDE=-I. -I${srcdir}
|
||||
CC=cc
|
||||
OBJECTS=tgp-net.o tgp-timers.o msglog.o telegram-base.o
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
.SUFFIXES: .c .h .o
|
||||
|
||||
|
||||
#
|
||||
# Plugin Flags
|
||||
#
|
||||
|
||||
LIBS_PURPLE = $(shell pkg-config --libs purple)
|
||||
CFLAGS_PURPLE = $(shell pkg-config --cflags purple)
|
||||
PLUGIN_DIR_PURPLE:=$(shell pkg-config --variable=plugindir purple)
|
||||
DATA_ROOT_DIR_PURPLE:=$(shell pkg-config --variable=datarootdir purple)
|
||||
|
||||
ARCH = ""
|
||||
ifeq ($(ARCH),i686)
|
||||
ARCHFLAGS = -m32
|
||||
else ifeq ($(ARCH),x86_64)
|
||||
ARCHFLAGS = -m64
|
||||
else
|
||||
ARCHFLAGS =
|
||||
endif
|
||||
|
||||
LD = $(CC)
|
||||
PRPL_C_SRCS = telegram-purple.c
|
||||
PRPL_C_OBJS = $(PRPL_C_SRCS:.c=.o)
|
||||
PRPL_LIBNAME = telegram-purple.so
|
||||
PRPL_INCLUDE = -I. -I./purple-plugin
|
||||
PRPL_LDFLAGS = $(ARCHFLAGS) -shared
|
||||
STRIP = strip
|
||||
PRPL_CFLAGS = \
|
||||
$(ARCHFLAGS) \
|
||||
-fPIC \
|
||||
-DPURPLE_PLUGINS \
|
||||
-DPIC \
|
||||
-DDEBUG \
|
||||
-g \
|
||||
$(CFLAGS_PURPLE)
|
||||
|
||||
#
|
||||
# Telegram Objects
|
||||
#
|
||||
|
||||
.c.o :
|
||||
${CC} -fPIC -DPIC ${CFLAGS_PURPLE} ${COMPILE_FLAGS} ${INCLUDE} -c $< -o $@
|
||||
|
||||
# ${OBJECTS}: ${HEADERS}
|
||||
|
||||
#telegram: ${OBJECTS}
|
||||
# ${CC} ${OBJECTS} ${LINK_FLAGS} -o $@
|
||||
|
||||
#
|
||||
# Plugin Objects
|
||||
#
|
||||
|
||||
$(PRPL_C_OBJS): $(PRPL_C_SRCS)
|
||||
$(CC) -c $(PRPL_INCLUDE) $(PRPL_CFLAGS) $(CFLAGS) $(CPPFLAGS) -ggdb -o $@ $<
|
||||
|
||||
$(PRPL_LIBNAME): $(OBJECTS) $(PRPL_C_OBJS) tg/libs/libtgl.a
|
||||
$(LD) $(PRPL_LDFLAGS) $(LDFLAGS) $(PRPL_INCLUDE) $(LIBS_PURPLE) $(EXTRA_LIBS) -o $@ $^
|
||||
|
||||
.PHONY: all
|
||||
all: ${PRPL_LIBNAME}
|
||||
|
||||
plugin: $(PRPL_LIBNAME)
|
||||
|
||||
|
||||
.PHONY: strip
|
||||
strip: $(PRPL_LIBNAME)
|
||||
$(STRIP) --strip-unneeded $(PRPL_LIBNAME)
|
||||
|
||||
# TODO: Find a better place for server.pub
|
||||
install: $(PRPL_LIBNAME)
|
||||
install -D $(PRPL_LIBNAME) $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME)
|
||||
install -D tg-server.pub /etc/telegram-purple/server.pub
|
||||
install -D imgs/telegram16.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png
|
||||
install -D imgs/telegram22.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png
|
||||
install -D imgs/telegram48.png $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(PLUGIN_DIR_PURPLE)/$(PRPL_LIBNAME)
|
||||
rm -f /etc/telegram-purple/server.pub
|
||||
rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/16/telegram.png
|
||||
rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/22/telegram.png
|
||||
rm -f $(DESTDIR)$(DATA_ROOT_DIR_PURPLE)/pixmaps/pidgin/protocols/48/telegram.png
|
||||
|
||||
.PHONY: run
|
||||
run: install
|
||||
pidgin -d | grep 'telegram\|plugin\|proxy'
|
||||
|
||||
.PHONY: purge
|
||||
purge: uninstall
|
||||
rm -rf $(HOME)/.telegram-purple
|
||||
|
||||
.PHONY: debug
|
||||
debug: install
|
||||
ddd pidgin
|
||||
|
||||
clean:
|
||||
rm -rf *.so *.a *.o telegram config.log config.status $(PRPL_C_OBJS) $(PRPL_LIBNAME) > /dev/null || echo "all clean"
|
||||
|
BIN
imgs/telegram.png
Normal file
BIN
imgs/telegram.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
imgs/telegram16.png
Normal file
BIN
imgs/telegram16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 671 B |
BIN
imgs/telegram22.png
Normal file
BIN
imgs/telegram22.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1 KiB |
BIN
imgs/telegram48.png
Normal file
BIN
imgs/telegram48.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
79
msglog.c
Normal file
79
msglog.c
Normal file
|
@ -0,0 +1,79 @@
|
|||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <debug.h>
|
||||
#include "telegram-purple.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#define COLOR_GREY "\033[37;1m"
|
||||
#define COLOR_YELLOW "\033[33;1m"
|
||||
#define COLOR_RED "\033[0;31m"
|
||||
#define COLOR_REDB "\033[1;31m"
|
||||
#define COLOR_GREEN "\033[32;1m"
|
||||
#define COLOR_NORMAL "\033[0m"
|
||||
#else
|
||||
#define COLOR_GREY ""
|
||||
#define COLOR_YELLOW ""
|
||||
#define COLOR_RED ""
|
||||
#define COLOR_REDB ""
|
||||
#define COLOR_GREEN ""
|
||||
#define COLOR_NORMAL ""
|
||||
#endif
|
||||
|
||||
void hexdump (int *in_ptr, int *in_end) {
|
||||
// TODO: figure out how to log hexdumps to purple log
|
||||
int *ptr = in_ptr;
|
||||
while (ptr < in_end) {
|
||||
++ ptr;
|
||||
//printf (" %08x", *(ptr ++));
|
||||
}
|
||||
//printf ("\n");
|
||||
}
|
||||
|
||||
void log_level_printf (const char* format, va_list ap, int level, char *color)
|
||||
{
|
||||
char buffer[256];
|
||||
vsnprintf(buffer, sizeof(buffer), format, ap);
|
||||
purple_debug(level, PLUGIN_ID, "%s%s%s ", color, buffer, COLOR_NORMAL);
|
||||
}
|
||||
|
||||
void debug(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
log_level_printf (format, ap, PURPLE_DEBUG_MISC, COLOR_NORMAL);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void info(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
log_level_printf (format, ap, PURPLE_DEBUG_INFO, COLOR_GREEN);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void warning(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
log_level_printf (format, ap, PURPLE_DEBUG_WARNING, COLOR_YELLOW);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void failure(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
log_level_printf (format, ap, PURPLE_DEBUG_ERROR, COLOR_YELLOW);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void fatal(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, format);
|
||||
log_level_printf (format, ap, PURPLE_DEBUG_FATAL, COLOR_REDB);
|
||||
va_end (ap);
|
||||
info ("\n");
|
||||
}
|
||||
|
14
msglog.h
Normal file
14
msglog.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Set a custom logging callback to use instead of regular printing
|
||||
* to stdout
|
||||
*/
|
||||
void hexdump (int *in_ptr, int *in_end);
|
||||
|
||||
void debug(const char* format, ...);
|
||||
void info(const char* format, ...);
|
||||
void warning(const char* format, ...);
|
||||
void failure(const char* format, ...);
|
||||
void fatal(const char* format, ...);
|
||||
|
372
telegram-base.c
Normal file
372
telegram-base.c
Normal file
|
@ -0,0 +1,372 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <tgl.h>
|
||||
#include <binlog.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <request.h>
|
||||
|
||||
#include "telegram-purple.h"
|
||||
#include "msglog.h"
|
||||
|
||||
#define DC_SERIALIZED_MAGIC 0x868aa81d
|
||||
#define STATE_FILE_MAGIC 0x28949a93
|
||||
#define SECRET_CHAT_FILE_MAGIC 0x37a1988a
|
||||
|
||||
|
||||
void read_state_file (struct tgl_state *TLS) {
|
||||
char *name = 0;
|
||||
if (asprintf (&name, "%s/%s", TLS->base_path, "state") < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int state_file_fd = open (name, O_CREAT | O_RDWR, 0600);
|
||||
free (name);
|
||||
|
||||
if (state_file_fd < 0) {
|
||||
return;
|
||||
}
|
||||
int version, magic;
|
||||
if (read (state_file_fd, &magic, 4) < 4) { close (state_file_fd); return; }
|
||||
if (magic != (int)STATE_FILE_MAGIC) { close (state_file_fd); return; }
|
||||
if (read (state_file_fd, &version, 4 || version < 0) < 4) { close (state_file_fd); return; }
|
||||
int x[4];
|
||||
if (read (state_file_fd, x, 16) < 16) {
|
||||
close (state_file_fd);
|
||||
return;
|
||||
}
|
||||
int pts = x[0];
|
||||
int qts = x[1];
|
||||
int seq = x[2];
|
||||
int date = x[3];
|
||||
close (state_file_fd);
|
||||
bl_do_set_seq (TLS, seq);
|
||||
bl_do_set_pts (TLS, pts);
|
||||
bl_do_set_qts (TLS, qts);
|
||||
bl_do_set_date (TLS, date);
|
||||
}
|
||||
|
||||
void write_state_file (struct tgl_state *TLS) {
|
||||
int wseq;
|
||||
int wpts;
|
||||
int wqts;
|
||||
int wdate;
|
||||
wseq = TLS->seq; wpts = TLS->pts; wqts = TLS->qts; wdate = TLS->date;
|
||||
|
||||
char *name = 0;
|
||||
if (asprintf (&name, "%s/%s", TLS->base_path, "state") < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int state_file_fd = open (name, O_CREAT | O_RDWR, 0600);
|
||||
free (name);
|
||||
|
||||
if (state_file_fd < 0) {
|
||||
return;
|
||||
}
|
||||
int x[6];
|
||||
x[0] = STATE_FILE_MAGIC;
|
||||
x[1] = 0;
|
||||
x[2] = wpts;
|
||||
x[3] = wqts;
|
||||
x[4] = wseq;
|
||||
x[5] = wdate;
|
||||
assert (write (state_file_fd, x, 24) == 24);
|
||||
close (state_file_fd);
|
||||
}
|
||||
|
||||
void write_dc (struct tgl_dc *DC, void *extra) {
|
||||
int auth_file_fd = *(int *)extra;
|
||||
if (!DC) {
|
||||
int x = 0;
|
||||
assert (write (auth_file_fd, &x, 4) == 4);
|
||||
return;
|
||||
} else {
|
||||
int x = 1;
|
||||
assert (write (auth_file_fd, &x, 4) == 4);
|
||||
}
|
||||
|
||||
assert (DC->has_auth);
|
||||
|
||||
assert (write (auth_file_fd, &DC->port, 4) == 4);
|
||||
int l = strlen (DC->ip);
|
||||
assert (write (auth_file_fd, &l, 4) == 4);
|
||||
assert (write (auth_file_fd, DC->ip, l) == l);
|
||||
assert (write (auth_file_fd, &DC->auth_key_id, 8) == 8);
|
||||
assert (write (auth_file_fd, DC->auth_key, 256) == 256);
|
||||
}
|
||||
|
||||
void write_auth_file (struct tgl_state *TLS) {
|
||||
char *name = 0;
|
||||
if (asprintf (&name, "%s/%s", TLS->base_path, "auth") < 0) {
|
||||
return;
|
||||
}
|
||||
int auth_file_fd = open (name, O_CREAT | O_RDWR, 0600);
|
||||
free (name);
|
||||
if (auth_file_fd < 0) { return; }
|
||||
int x = DC_SERIALIZED_MAGIC;
|
||||
assert (write (auth_file_fd, &x, 4) == 4);
|
||||
assert (write (auth_file_fd, &TLS->max_dc_num, 4) == 4);
|
||||
assert (write (auth_file_fd, &TLS->dc_working_num, 4) == 4);
|
||||
|
||||
tgl_dc_iterator_ex (TLS, write_dc, &auth_file_fd);
|
||||
|
||||
assert (write (auth_file_fd, &TLS->our_id, 4) == 4);
|
||||
close (auth_file_fd);
|
||||
}
|
||||
|
||||
void read_dc (struct tgl_state *TLS, int auth_file_fd, int id, unsigned ver) {
|
||||
int port = 0;
|
||||
assert (read (auth_file_fd, &port, 4) == 4);
|
||||
int l = 0;
|
||||
assert (read (auth_file_fd, &l, 4) == 4);
|
||||
assert (l >= 0 && l < 100);
|
||||
char ip[100];
|
||||
assert (read (auth_file_fd, ip, l) == l);
|
||||
ip[l] = 0;
|
||||
|
||||
long long auth_key_id;
|
||||
static unsigned char auth_key[256];
|
||||
assert (read (auth_file_fd, &auth_key_id, 8) == 8);
|
||||
assert (read (auth_file_fd, auth_key, 256) == 256);
|
||||
|
||||
//bl_do_add_dc (id, ip, l, port, auth_key_id, auth_key);
|
||||
bl_do_dc_option (TLS, id, 2, "DC", l, ip, port);
|
||||
bl_do_set_auth_key_id (TLS, id, auth_key);
|
||||
bl_do_dc_signed (TLS, id);
|
||||
}
|
||||
|
||||
void empty_auth_file (struct tgl_state *TLS) {
|
||||
if (TLS->test_mode) {
|
||||
bl_do_dc_option (TLS, 1, 0, "", strlen (TG_SERVER_TEST_1), TG_SERVER_TEST_1, 443);
|
||||
bl_do_dc_option (TLS, 2, 0, "", strlen (TG_SERVER_TEST_2), TG_SERVER_TEST_2, 443);
|
||||
bl_do_dc_option (TLS, 3, 0, "", strlen (TG_SERVER_TEST_3), TG_SERVER_TEST_3, 443);
|
||||
bl_do_set_working_dc (TLS, TG_SERVER_TEST_DEFAULT);
|
||||
} else {
|
||||
bl_do_dc_option (TLS, 1, 0, "", strlen (TG_SERVER_1), TG_SERVER_1, 443);
|
||||
bl_do_dc_option (TLS, 2, 0, "", strlen (TG_SERVER_2), TG_SERVER_2, 443);
|
||||
bl_do_dc_option (TLS, 3, 0, "", strlen (TG_SERVER_3), TG_SERVER_3, 443);
|
||||
bl_do_dc_option (TLS, 4, 0, "", strlen (TG_SERVER_4), TG_SERVER_4, 443);
|
||||
bl_do_dc_option (TLS, 5, 0, "", strlen (TG_SERVER_5), TG_SERVER_5, 443);
|
||||
bl_do_set_working_dc (TLS, TG_SERVER_DEFAULT);;
|
||||
}
|
||||
}
|
||||
|
||||
void read_auth_file (struct tgl_state *TLS) {
|
||||
char *name = 0;
|
||||
if (asprintf (&name, "%s/%s", TLS->base_path, "auth") < 0) {
|
||||
return;
|
||||
}
|
||||
int auth_file_fd = open (name, O_CREAT | O_RDWR, 0600);
|
||||
free (name);
|
||||
if (auth_file_fd < 0) {
|
||||
empty_auth_file (TLS);
|
||||
return;
|
||||
}
|
||||
assert (auth_file_fd >= 0);
|
||||
unsigned x;
|
||||
unsigned m;
|
||||
if (read (auth_file_fd, &m, 4) < 4 || (m != DC_SERIALIZED_MAGIC)) {
|
||||
close (auth_file_fd);
|
||||
empty_auth_file (TLS);
|
||||
return;
|
||||
}
|
||||
assert (read (auth_file_fd, &x, 4) == 4);
|
||||
assert (x > 0);
|
||||
int dc_working_num;
|
||||
assert (read (auth_file_fd, &dc_working_num, 4) == 4);
|
||||
|
||||
int i;
|
||||
for (i = 0; i <= (int)x; i++) {
|
||||
int y;
|
||||
assert (read (auth_file_fd, &y, 4) == 4);
|
||||
if (y) {
|
||||
read_dc (TLS, auth_file_fd, i, m);
|
||||
}
|
||||
}
|
||||
bl_do_set_working_dc (TLS, dc_working_num);
|
||||
int our_id;
|
||||
int l = read (auth_file_fd, &our_id, 4);
|
||||
if (l < 4) {
|
||||
assert (!l);
|
||||
}
|
||||
if (our_id) {
|
||||
bl_do_set_our_id (TLS, our_id);
|
||||
}
|
||||
close (auth_file_fd);
|
||||
}
|
||||
|
||||
void telegram_export_authorization (struct tgl_state *TLS);
|
||||
void export_auth_callback (struct tgl_state *TLS, void *extra, int success) {
|
||||
assert (success);
|
||||
telegram_export_authorization (TLS);
|
||||
}
|
||||
|
||||
void telegram_export_authorization (struct tgl_state *TLS) {
|
||||
int i;
|
||||
for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i] && !tgl_signed_dc (TLS, TLS->DC_list[i])) {
|
||||
tgl_do_export_auth (TLS, i, export_auth_callback, (void*)(long)TLS->DC_list[i]);
|
||||
return;
|
||||
}
|
||||
write_auth_file (TLS);
|
||||
telegram_on_ready (TLS);
|
||||
}
|
||||
|
||||
static void request_code (struct tgl_state *TLS);
|
||||
static void request_name_and_code (struct tgl_state *TLS);
|
||||
static void code_receive_result (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U) {
|
||||
if (!success) {
|
||||
debug ("Bad code...\n");
|
||||
request_code (TLS);
|
||||
} else {
|
||||
telegram_export_authorization (TLS);
|
||||
}
|
||||
}
|
||||
|
||||
static void code_auth_receive_result (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U) {
|
||||
if (!success) {
|
||||
debug ("Bad code...\n");
|
||||
request_name_and_code (TLS);
|
||||
} else {
|
||||
telegram_export_authorization (TLS);
|
||||
}
|
||||
}
|
||||
|
||||
static void request_code_entered (gpointer data, const gchar *code) {
|
||||
struct tgl_state *TLS = data;
|
||||
telegram_conn *conn = TLS->ev_base;
|
||||
char const *username = purple_account_get_username(conn->pa);
|
||||
tgl_do_send_code_result (TLS, username, conn->hash, code, code_receive_result, 0) ;
|
||||
}
|
||||
|
||||
static void request_code_canceled (gpointer data) {
|
||||
struct tgl_state *TLS = data;
|
||||
telegram_conn *conn = TLS->ev_base;
|
||||
|
||||
purple_connection_error_reason(conn->gc,
|
||||
PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, "registration canceled");
|
||||
}
|
||||
|
||||
static void request_name_code_entered (PurpleConnection* gc, PurpleRequestFields* fields) {
|
||||
telegram_conn *conn = purple_connection_get_protocol_data(gc);
|
||||
struct tgl_state *TLS = conn->TLS;
|
||||
char const *username = purple_account_get_username(conn->pa);
|
||||
|
||||
const char* first = purple_request_fields_get_string(fields, "first_name");
|
||||
const char* last = purple_request_fields_get_string(fields, "last_name");
|
||||
const char* code = purple_request_fields_get_string(fields, "code");
|
||||
if (!first || !last || !code) {
|
||||
request_name_and_code (TLS);
|
||||
return;
|
||||
}
|
||||
|
||||
tgl_do_send_code_result_auth (TLS, username, conn->hash, code, first, last, code_auth_receive_result, NULL);
|
||||
}
|
||||
|
||||
static void request_code (struct tgl_state *TLS) {
|
||||
debug ("Client is not registered, registering...\n");
|
||||
telegram_conn *conn = TLS->ev_base;
|
||||
|
||||
purple_request_input (
|
||||
conn->gc, // handle (the PurpleAccount)
|
||||
"Telegram Code", // title
|
||||
"Enter Telegram Code", // primary
|
||||
"Telegram wants to verify your identity, please enter the code, that you have received via SMS.", // secondary
|
||||
NULL, // default_value
|
||||
0, // multiline
|
||||
0, // masked
|
||||
"code", // hint
|
||||
"OK", // ok_text
|
||||
G_CALLBACK(request_code_entered), // ok_cb
|
||||
"Cancel", // cancel_text
|
||||
G_CALLBACK(request_code_canceled), // cancel_cb
|
||||
conn->pa, // account
|
||||
NULL, // who
|
||||
NULL, // conv
|
||||
TLS // user_data
|
||||
);
|
||||
}
|
||||
|
||||
static void request_name_and_code (struct tgl_state *TLS) {
|
||||
telegram_conn *conn = TLS->ev_base;
|
||||
|
||||
debug ("Phone is not registered, registering...\n");
|
||||
|
||||
PurpleRequestFields* fields = purple_request_fields_new();
|
||||
PurpleRequestField* field = 0;
|
||||
|
||||
PurpleRequestFieldGroup* group = purple_request_field_group_new("Registration");
|
||||
field = purple_request_field_string_new("first_name", "First Name", "", 0);
|
||||
purple_request_field_group_add_field(group, field);
|
||||
field = purple_request_field_string_new("last_name", "Last Name", "", 0);
|
||||
purple_request_field_group_add_field(group, field);
|
||||
purple_request_fields_add_group(fields, group);
|
||||
|
||||
group = purple_request_field_group_new("Authorization");
|
||||
field = purple_request_field_string_new("code", "Telegram Code", "", 0);
|
||||
purple_request_field_group_add_field(group, field);
|
||||
purple_request_fields_add_group(fields, group);
|
||||
|
||||
purple_request_fields(conn->gc, "Register", "Please register your phone number.", NULL, fields, "Ok",
|
||||
G_CALLBACK( request_name_code_entered ), "Cancel", NULL, conn->pa, NULL, NULL, conn->gc);
|
||||
}
|
||||
|
||||
static void sign_in_callback (struct tgl_state *TLS, void *extra, int success, int registered, const char *mhash) {
|
||||
assert (success); // TODO proper error handle
|
||||
telegram_conn *conn = TLS->ev_base;
|
||||
conn->hash = strdup (mhash);
|
||||
|
||||
if (registered) {
|
||||
request_code (TLS);
|
||||
} else {
|
||||
request_name_and_code (TLS);
|
||||
}
|
||||
}
|
||||
|
||||
static void telegram_send_sms (struct tgl_state *TLS) {
|
||||
if (tgl_signed_dc (TLS, TLS->DC_working)) {
|
||||
telegram_export_authorization (TLS);
|
||||
return;
|
||||
}
|
||||
telegram_conn *conn = TLS->ev_base;
|
||||
char const *username = purple_account_get_username(conn->pa);
|
||||
tgl_do_send_code (TLS, username, sign_in_callback, 0);
|
||||
}
|
||||
|
||||
static int all_authorized (struct tgl_state *TLS) {
|
||||
int i;
|
||||
for (i = 0; i <= TLS->max_dc_num; i++) if (TLS->DC_list[i]) {
|
||||
if (!tgl_authorized_dc (TLS, TLS->DC_list[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_all_authorized (gpointer arg) {
|
||||
struct tgl_state *TLS = arg;
|
||||
if (all_authorized (TLS)) {
|
||||
telegram_send_sms (TLS);
|
||||
return FALSE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
void telegram_login (struct tgl_state *TLS) {
|
||||
read_auth_file (TLS);
|
||||
read_state_file (TLS);
|
||||
if (all_authorized (TLS)) {
|
||||
telegram_send_sms (TLS);
|
||||
return;
|
||||
}
|
||||
purple_timeout_add (100, check_all_authorized, TLS);
|
||||
}
|
||||
|
9
telegram-base.h
Normal file
9
telegram-base.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#ifndef __TELEGRAM_BASE_H__
|
||||
#define __TELEGRAM_BASE_H__
|
||||
void read_state_file (struct tgl_state *TLS);
|
||||
void read_auth_file (struct tgl_state *TLS);
|
||||
void write_auth_file (struct tgl_state *TLS);
|
||||
void write_state_file (struct tgl_state *TLS);
|
||||
|
||||
void telegram_login (struct tgl_state *TLS);
|
||||
#endif
|
1082
telegram-purple.c
Normal file
1082
telegram-purple.c
Normal file
File diff suppressed because it is too large
Load diff
70
telegram-purple.h
Normal file
70
telegram-purple.h
Normal file
|
@ -0,0 +1,70 @@
|
|||
/**
|
||||
* This program 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 2 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef __TG_PURPLE_H__
|
||||
#define __TG_PURPLE_H__
|
||||
|
||||
#define PLUGIN_ID "prpl-telegram"
|
||||
#define TELEGRAM_AUTH_MODE_PHONE "phone"
|
||||
#define TELEGRAM_AUTH_MODE_SMS "sms"
|
||||
#define TG_AUTHOR "Christopher Althaus <althaus.christopher@gmail.com>, Markus Endres <endresma45241@th-nuernberg.de>, Matthias Jentsch <mtthsjntsch@gmail.com>. Based on telegram-cli by Vitaly Valtman."
|
||||
#define TG_DESCRIPTION "Adds support for Telegram."
|
||||
#define TG_VERSION "0.3.3"
|
||||
#define TG_BUILD "8"
|
||||
|
||||
#include <glib.h>
|
||||
#include <notify.h>
|
||||
#include <plugin.h>
|
||||
#include <version.h>
|
||||
#include <account.h>
|
||||
#include <connection.h>
|
||||
|
||||
typedef struct {
|
||||
struct tgl_state *TLS;
|
||||
|
||||
/*
|
||||
* Used during login
|
||||
*/
|
||||
char *hash;
|
||||
|
||||
PurpleAccount *pa;
|
||||
PurpleConnection *gc;
|
||||
|
||||
/**
|
||||
* Whether the state of the protocol has changed since the last save
|
||||
*/
|
||||
int updated;
|
||||
|
||||
/**
|
||||
* Queue of all new messages that need to be added to a chat
|
||||
*/
|
||||
GQueue *new_messages;
|
||||
|
||||
/**
|
||||
* Queue of all joined chats
|
||||
*/
|
||||
GHashTable *joining_chats;
|
||||
|
||||
guint timer;
|
||||
} telegram_conn;
|
||||
|
||||
struct download_desc {
|
||||
int type;
|
||||
void *data;
|
||||
};
|
||||
|
||||
void telegram_on_ready (struct tgl_state *TLS);
|
||||
#endif
|
8
tg-server.pub
Normal file
8
tg-server.pub
Normal file
|
@ -0,0 +1,8 @@
|
|||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIIBCgKCAQEAwVACPi9w23mF3tBkdZz+zwrzKOaaQdr01vAbU4E1pvkfj4sqDsm6
|
||||
lyDONS789sVoD/xCS9Y0hkkC3gtL1tSfTlgCMOOul9lcixlEKzwKENj1Yz/s7daS
|
||||
an9tqw3bfUV/nqgbhGX81v/+7RFAEd+RwFnK7a+XYl9sluzHRyVVaTTveB2GazTw
|
||||
Efzk2DWgkBluml8OREmvfraX3bkHZJTKX4EQSjBbbdJ2ZXIsRrYOXfaA+xayEGB+
|
||||
8hdlLmAjbCVfaigxX0CDqWeR1yFL9kwd9P0NsZRPsmoqVwMbMu7mStFai6aIhc3n
|
||||
Slv8kg9qv1m6XHVQY3PnEw+QQtqSIXklHwIDAQAB
|
||||
-----END RSA PUBLIC KEY-----
|
584
tgp-net.c
Normal file
584
tgp-net.c
Normal file
|
@ -0,0 +1,584 @@
|
|||
/*
|
||||
This file is part of tgl-library
|
||||
|
||||
This library 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 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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 library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Copyright Vitaly Valtman 2013-2014
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <openssl/rand.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/time.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "tgp-net.h"
|
||||
//#include "include.h"
|
||||
#include <tgl.h>
|
||||
#include <tgl-inner.h>
|
||||
//#include "mtproto-client.h"
|
||||
//#include "mtproto-common.h"
|
||||
//#include "tree.h"
|
||||
//#include "tools.h"
|
||||
|
||||
#include <glib.h>
|
||||
#include <eventloop.h>
|
||||
|
||||
#include "telegram-purple.h"
|
||||
|
||||
#ifndef POLLRDHUP
|
||||
#define POLLRDHUP 0
|
||||
#endif
|
||||
|
||||
//double get_utime (int clock_id);
|
||||
|
||||
//extern struct mtproto_methods auth_methods;
|
||||
|
||||
static void fail_connection (struct connection *c);
|
||||
|
||||
#define PING_TIMEOUT 10
|
||||
|
||||
static void start_ping_timer (struct connection *c);
|
||||
static int ping_alarm (gpointer arg) {
|
||||
struct connection *c = arg;
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
vlogprintf (E_DEBUG + 2,"ping alarm\n");
|
||||
assert (c->state == conn_ready || c->state == conn_connecting);
|
||||
if (tglt_get_double_time () - c->last_receive_time > 6 * PING_TIMEOUT) {
|
||||
vlogprintf (E_WARNING, "fail connection: reason: ping timeout\n");
|
||||
c->state = conn_failed;
|
||||
fail_connection (c);
|
||||
return FALSE;
|
||||
} else if (tglt_get_double_time () - c->last_receive_time > 3 * PING_TIMEOUT && c->state == conn_ready) {
|
||||
tgl_do_send_ping (c->TLS, c);
|
||||
return TRUE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void stop_ping_timer (struct connection *c) {
|
||||
purple_timeout_remove (c->ping_ev);
|
||||
}
|
||||
|
||||
static void start_ping_timer (struct connection *c) {
|
||||
c->ping_ev = purple_timeout_add_seconds (PING_TIMEOUT, ping_alarm, c);
|
||||
}
|
||||
|
||||
static void restart_connection (struct connection *c);
|
||||
|
||||
static int fail_alarm (gpointer arg) {
|
||||
struct connection *c = arg;
|
||||
c->in_fail_timer = 0;
|
||||
restart_connection (c);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void start_fail_timer (struct connection *c) {
|
||||
if (c->in_fail_timer) { return; }
|
||||
c->in_fail_timer = 1;
|
||||
|
||||
c->fail_ev = purple_timeout_add_seconds (10, fail_alarm, c);
|
||||
}
|
||||
|
||||
static struct connection_buffer *new_connection_buffer (int size) {
|
||||
struct connection_buffer *b = malloc (sizeof (*b));
|
||||
memset (b, 0, sizeof (*b));
|
||||
b->start = malloc (size);
|
||||
b->end = b->start + size;
|
||||
b->rptr = b->wptr = b->start;
|
||||
return b;
|
||||
}
|
||||
|
||||
static void delete_connection_buffer (struct connection_buffer *b) {
|
||||
free (b->start);
|
||||
free (b);
|
||||
}
|
||||
|
||||
static void conn_try_write (gpointer arg, gint source, PurpleInputCondition cond);
|
||||
int tgln_write_out (struct connection *c, const void *_data, int len) {
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
vlogprintf (E_DEBUG, "write_out: %d bytes\n", len);
|
||||
const unsigned char *data = _data;
|
||||
if (!len) { return 0; }
|
||||
assert (len > 0);
|
||||
int x = 0;
|
||||
if (!c->out_bytes) {
|
||||
assert (c->write_ev == -1);
|
||||
c->write_ev = purple_input_add (c->fd, PURPLE_INPUT_WRITE, conn_try_write, c);
|
||||
}
|
||||
if (!c->out_head) {
|
||||
struct connection_buffer *b = new_connection_buffer (1 << 20);
|
||||
c->out_head = c->out_tail = b;
|
||||
}
|
||||
while (len) {
|
||||
if (c->out_tail->end - c->out_tail->wptr >= len) {
|
||||
memcpy (c->out_tail->wptr, data, len);
|
||||
c->out_tail->wptr += len;
|
||||
c->out_bytes += len;
|
||||
return x + len;
|
||||
} else {
|
||||
int y = c->out_tail->end - c->out_tail->wptr;
|
||||
assert (y < len);
|
||||
memcpy (c->out_tail->wptr, data, y);
|
||||
x += y;
|
||||
len -= y;
|
||||
data += y;
|
||||
struct connection_buffer *b = new_connection_buffer (1 << 20);
|
||||
c->out_tail->next = b;
|
||||
b->next = 0;
|
||||
c->out_tail = b;
|
||||
c->out_bytes += y;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int tgln_read_in (struct connection *c, void *_data, int len) {
|
||||
unsigned char *data = _data;
|
||||
if (!len) { return 0; }
|
||||
assert (len > 0);
|
||||
if (len > c->in_bytes) {
|
||||
len = c->in_bytes;
|
||||
}
|
||||
int x = 0;
|
||||
while (len) {
|
||||
int y = c->in_head->wptr - c->in_head->rptr;
|
||||
if (y > len) {
|
||||
memcpy (data, c->in_head->rptr, len);
|
||||
c->in_head->rptr += len;
|
||||
c->in_bytes -= len;
|
||||
return x + len;
|
||||
} else {
|
||||
memcpy (data, c->in_head->rptr, y);
|
||||
c->in_bytes -= y;
|
||||
x += y;
|
||||
data += y;
|
||||
len -= y;
|
||||
void *old = c->in_head;
|
||||
c->in_head = c->in_head->next;
|
||||
if (!c->in_head) {
|
||||
c->in_tail = 0;
|
||||
}
|
||||
delete_connection_buffer (old);
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int tgln_read_in_lookup (struct connection *c, void *_data, int len) {
|
||||
unsigned char *data = _data;
|
||||
if (!len || !c->in_bytes) { return 0; }
|
||||
assert (len > 0);
|
||||
if (len > c->in_bytes) {
|
||||
len = c->in_bytes;
|
||||
}
|
||||
int x = 0;
|
||||
struct connection_buffer *b = c->in_head;
|
||||
while (len) {
|
||||
int y = b->wptr - b->rptr;
|
||||
if (y >= len) {
|
||||
memcpy (data, b->rptr, len);
|
||||
return x + len;
|
||||
} else {
|
||||
memcpy (data, b->rptr, y);
|
||||
x += y;
|
||||
data += y;
|
||||
len -= y;
|
||||
b = b->next;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
void tgln_flush_out (struct connection *c) {
|
||||
}
|
||||
|
||||
//#define MAX_CONNECTIONS 100
|
||||
//static struct connection *Connections[MAX_CONNECTIONS];
|
||||
//static int max_connection_fd;
|
||||
|
||||
static void rotate_port (struct connection *c) {
|
||||
switch (c->port) {
|
||||
case 443:
|
||||
c->port = 80;
|
||||
break;
|
||||
case 80:
|
||||
c->port = 25;
|
||||
break;
|
||||
case 25:
|
||||
c->port = 443;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void try_read (struct connection *c);
|
||||
static void try_write (struct connection *c);
|
||||
|
||||
static void conn_try_read (gpointer arg, gint source, PurpleInputCondition cond) {
|
||||
struct connection *c = arg;
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
vlogprintf (E_DEBUG + 1, "Try read. Fd = %d\n", c->fd);
|
||||
try_read (c);
|
||||
}
|
||||
|
||||
static void conn_try_write (gpointer arg, gint source, PurpleInputCondition cond) {
|
||||
struct connection *c = arg;
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
if (c->state == conn_connecting) {
|
||||
c->state = conn_ready;
|
||||
c->methods->ready (TLS, c);
|
||||
}
|
||||
try_write (c);
|
||||
if (!c->out_bytes) {
|
||||
purple_input_remove (c->write_ev);
|
||||
c->write_ev = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void net_on_connected (gpointer arg, gint fd, const gchar *error_message) {
|
||||
struct connection *c = arg;
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
vlogprintf (E_DEBUG - 2, "connect result: %d\n", fd);
|
||||
|
||||
if (fd == -1) {
|
||||
fail_connection (c);
|
||||
return;
|
||||
}
|
||||
|
||||
c->fd = fd;
|
||||
c->read_ev = purple_input_add (fd, PURPLE_INPUT_READ, conn_try_read, c);
|
||||
|
||||
char byte = 0xef;
|
||||
assert (tgln_write_out (c, &byte, 1) == 1);
|
||||
|
||||
c->last_receive_time = tglt_get_double_time ();
|
||||
start_ping_timer (c);
|
||||
}
|
||||
|
||||
struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods) {
|
||||
struct connection *c = malloc (sizeof (*c));
|
||||
memset (c, 0, sizeof (*c));
|
||||
c->TLS = TLS;
|
||||
|
||||
|
||||
c->fd = -1;
|
||||
c->state = conn_connecting;
|
||||
|
||||
c->last_receive_time = tglt_get_double_time ();
|
||||
c->ip = strdup (host);
|
||||
c->flags = 0;
|
||||
c->port = port;
|
||||
|
||||
c->ping_ev = -1;
|
||||
c->fail_ev = -1;
|
||||
c->write_ev = -1;
|
||||
c->read_ev = -1;
|
||||
|
||||
c->dc = dc;
|
||||
c->session = session;
|
||||
c->methods = methods;
|
||||
|
||||
telegram_conn *conn = TLS->ev_base;
|
||||
c->prpl_data = purple_proxy_connect (conn->gc, conn->pa, host, port, net_on_connected, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
static void restart_connection (struct connection *c) {
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
if (c->last_connect_time == time (0)) {
|
||||
start_fail_timer (c);
|
||||
return;
|
||||
}
|
||||
|
||||
telegram_conn *conn = TLS->ev_base;
|
||||
c->prpl_data = purple_proxy_connect (conn->gc, conn->pa, c->ip, c->port, net_on_connected, c);
|
||||
}
|
||||
|
||||
static void fail_connection (struct connection *c) {
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
if (c->state == conn_ready) {
|
||||
stop_ping_timer (c);
|
||||
}
|
||||
if (c->write_ev >= 0) {
|
||||
purple_input_remove (c->write_ev);
|
||||
c->write_ev = -1;
|
||||
}
|
||||
if (c->read_ev >= 0) {
|
||||
purple_input_remove (c->write_ev);
|
||||
c->read_ev = -1;
|
||||
}
|
||||
|
||||
rotate_port (c);
|
||||
|
||||
struct connection_buffer *b = c->out_head;
|
||||
while (b) {
|
||||
struct connection_buffer *d = b;
|
||||
b = b->next;
|
||||
delete_connection_buffer (d);
|
||||
}
|
||||
b = c->in_head;
|
||||
while (b) {
|
||||
struct connection_buffer *d = b;
|
||||
b = b->next;
|
||||
delete_connection_buffer (d);
|
||||
}
|
||||
c->out_head = c->out_tail = c->in_head = c->in_tail = 0;
|
||||
c->state = conn_failed;
|
||||
c->out_bytes = c->in_bytes = 0;
|
||||
|
||||
if (c->state == conn_ready) {
|
||||
telegram_conn *conn = TLS->ev_base;
|
||||
purple_connection_error_reason(conn->gc, PURPLE_CONNECTION_ERROR_OTHER_ERROR, "connection fail");
|
||||
}
|
||||
c->prpl_data = NULL; // Did not find any destroy code. What should be done here?
|
||||
|
||||
vlogprintf (E_NOTICE, "Lost connection to server... %s:%d\n", c->ip, c->port);
|
||||
restart_connection (c);
|
||||
}
|
||||
|
||||
//extern FILE *log_net_f;
|
||||
static void try_write (struct connection *c) {
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
vlogprintf (E_DEBUG, "try write: fd = %d\n", c->fd);
|
||||
int x = 0;
|
||||
while (c->out_head) {
|
||||
int r = write (c->fd, c->out_head->rptr, c->out_head->wptr - c->out_head->rptr);
|
||||
if (r >= 0) {
|
||||
x += r;
|
||||
c->out_head->rptr += r;
|
||||
if (c->out_head->rptr != c->out_head->wptr) {
|
||||
break;
|
||||
}
|
||||
struct connection_buffer *b = c->out_head;
|
||||
c->out_head = b->next;
|
||||
if (!c->out_head) {
|
||||
c->out_tail = 0;
|
||||
}
|
||||
delete_connection_buffer (b);
|
||||
} else {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
vlogprintf (E_NOTICE, "fail_connection: write_error %m\n");
|
||||
fail_connection (c);
|
||||
return;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vlogprintf (E_DEBUG, "Sent %d bytes to %d\n", x, c->fd);
|
||||
c->out_bytes -= x;
|
||||
}
|
||||
|
||||
static void try_rpc_read (struct connection *c) {
|
||||
assert (c->in_head);
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
|
||||
while (1) {
|
||||
if (c->in_bytes < 1) { return; }
|
||||
unsigned len = 0;
|
||||
unsigned t = 0;
|
||||
assert (tgln_read_in_lookup (c, &len, 1) == 1);
|
||||
if (len >= 1 && len <= 0x7e) {
|
||||
if (c->in_bytes < (int)(1 + 4 * len)) { return; }
|
||||
} else {
|
||||
if (c->in_bytes < 4) { return; }
|
||||
assert (tgln_read_in_lookup (c, &len, 4) == 4);
|
||||
len = (len >> 8);
|
||||
if (c->in_bytes < (int)(4 + 4 * len)) { return; }
|
||||
len = 0x7f;
|
||||
}
|
||||
|
||||
if (len >= 1 && len <= 0x7e) {
|
||||
assert (tgln_read_in (c, &t, 1) == 1);
|
||||
assert (t == len);
|
||||
assert (len >= 1);
|
||||
} else {
|
||||
assert (len == 0x7f);
|
||||
assert (tgln_read_in (c, &len, 4) == 4);
|
||||
len = (len >> 8);
|
||||
assert (len >= 1);
|
||||
}
|
||||
len *= 4;
|
||||
int op;
|
||||
assert (tgln_read_in_lookup (c, &op, 4) == 4);
|
||||
c->methods->execute (TLS, c, op, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void try_read (struct connection *c) {
|
||||
struct tgl_state *TLS = c->TLS;
|
||||
vlogprintf (E_DEBUG, "try read: fd = %d\n", c->fd);
|
||||
if (!c->in_tail) {
|
||||
c->in_head = c->in_tail = new_connection_buffer (1 << 20);
|
||||
}
|
||||
#ifdef EVENT_V1
|
||||
struct timeval tv = {5, 0};
|
||||
event_add (c->read_ev, &tv);
|
||||
#endif
|
||||
int x = 0;
|
||||
while (1) {
|
||||
int r = read (c->fd, c->in_tail->wptr, c->in_tail->end - c->in_tail->wptr);
|
||||
if (r > 0) {
|
||||
c->last_receive_time = tglt_get_double_time ();
|
||||
stop_ping_timer (c);
|
||||
start_ping_timer (c);
|
||||
}
|
||||
if (r >= 0) {
|
||||
c->in_tail->wptr += r;
|
||||
x += r;
|
||||
if (c->in_tail->wptr != c->in_tail->end) {
|
||||
break;
|
||||
}
|
||||
struct connection_buffer *b = new_connection_buffer (1 << 20);
|
||||
c->in_tail->next = b;
|
||||
c->in_tail = b;
|
||||
} else {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
vlogprintf (E_NOTICE, "fail_connection: read_error %m\n");
|
||||
fail_connection (c);
|
||||
return;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
vlogprintf (E_DEBUG, "Received %d bytes from %d\n", x, c->fd);
|
||||
c->in_bytes += x;
|
||||
if (x) {
|
||||
try_rpc_read (c);
|
||||
}
|
||||
}
|
||||
/*
|
||||
int tgl_connections_make_poll_array (struct pollfd *fds, int max) {
|
||||
int _max = max;
|
||||
int i;
|
||||
for (i = 0; i <= max_connection_fd; i++) {
|
||||
if (Connections[i] && Connections[i]->state == conn_failed) {
|
||||
restart_connection (Connections[i]);
|
||||
}
|
||||
if (Connections[i] && Connections[i]->state != conn_failed) {
|
||||
assert (max > 0);
|
||||
struct connection *c = Connections[i];
|
||||
fds[0].fd = c->fd;
|
||||
fds[0].events = POLLERR | POLLHUP | POLLRDHUP | POLLIN;
|
||||
if (c->out_bytes || c->state == conn_connecting) {
|
||||
fds[0].events |= POLLOUT;
|
||||
}
|
||||
fds ++;
|
||||
max --;
|
||||
}
|
||||
}
|
||||
return _max - max;
|
||||
}
|
||||
|
||||
void tgl_connections_poll_result (struct pollfd *fds, int max) {
|
||||
int i;
|
||||
for (i = 0; i < max; i++) {
|
||||
struct connection *c = Connections[fds[i].fd];
|
||||
if (fds[i].revents & POLLIN) {
|
||||
try_read (c);
|
||||
}
|
||||
if (fds[i].revents & (POLLHUP | POLLERR | POLLRDHUP)) {
|
||||
vlogprintf (E_NOTICE, "fail_connection: events_mask=0x%08x\n", fds[i].revents);
|
||||
fail_connection (c);
|
||||
} else if (fds[i].revents & POLLOUT) {
|
||||
if (c->state == conn_connecting) {
|
||||
vlogprintf (E_DEBUG, "connection ready\n");
|
||||
c->state = conn_ready;
|
||||
c->last_receive_time = tglt_get_double_time ();
|
||||
}
|
||||
if (c->out_bytes) {
|
||||
try_write (c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
static void incr_out_packet_num (struct connection *c) {
|
||||
c->out_packet_num ++;
|
||||
}
|
||||
|
||||
static struct tgl_dc *get_dc (struct connection *c) {
|
||||
return c->dc;
|
||||
}
|
||||
|
||||
static struct tgl_session *get_session (struct connection *c) {
|
||||
return c->session;
|
||||
}
|
||||
|
||||
static void tgln_free (struct connection *c) {
|
||||
if (c->ip) { free (c->ip); }
|
||||
struct connection_buffer *b = c->out_head;
|
||||
while (b) {
|
||||
struct connection_buffer *d = b;
|
||||
b = b->next;
|
||||
delete_connection_buffer (d);
|
||||
}
|
||||
b = c->in_head;
|
||||
while (b) {
|
||||
struct connection_buffer *d = b;
|
||||
b = b->next;
|
||||
delete_connection_buffer (d);
|
||||
}
|
||||
|
||||
if (c->ping_ev >= 0) {
|
||||
purple_timeout_remove (c->ping_ev);
|
||||
c->ping_ev = -1;
|
||||
}
|
||||
if (c->fail_ev >= 0) {
|
||||
purple_timeout_remove (c->fail_ev);
|
||||
c->fail_ev = -1;
|
||||
}
|
||||
|
||||
if (c->read_ev >= 0) {
|
||||
purple_input_remove (c->read_ev);
|
||||
}
|
||||
if (c->write_ev >= 0) {
|
||||
purple_input_remove (c->write_ev);
|
||||
}
|
||||
|
||||
c->fd = -1;
|
||||
}
|
||||
|
||||
struct tgl_net_methods tgp_conn_methods = {
|
||||
.write_out = tgln_write_out,
|
||||
.read_in = tgln_read_in,
|
||||
.read_in_lookup = tgln_read_in_lookup,
|
||||
.flush_out = tgln_flush_out,
|
||||
.incr_out_packet_num = incr_out_packet_num,
|
||||
.get_dc = get_dc,
|
||||
.get_session = get_session,
|
||||
.create_connection = tgln_create_connection,
|
||||
.free = tgln_free
|
||||
};
|
88
tgp-net.h
Normal file
88
tgp-net.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
This file is part of tgl-library
|
||||
|
||||
This library 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 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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 library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Copyright Vitaly Valtman 2013-2014
|
||||
*/
|
||||
#ifndef __NET_H__
|
||||
#define __NET_H__
|
||||
|
||||
struct connection_buffer {
|
||||
unsigned char *start;
|
||||
unsigned char *end;
|
||||
unsigned char *rptr;
|
||||
unsigned char *wptr;
|
||||
struct connection_buffer *next;
|
||||
};
|
||||
|
||||
enum conn_state {
|
||||
conn_none,
|
||||
conn_connecting,
|
||||
conn_ready,
|
||||
conn_failed,
|
||||
conn_stopped
|
||||
};
|
||||
|
||||
struct connection {
|
||||
int fd;
|
||||
char *ip;
|
||||
int port;
|
||||
int flags;
|
||||
enum conn_state state;
|
||||
int ipv6[4];
|
||||
struct connection_buffer *in_head;
|
||||
struct connection_buffer *in_tail;
|
||||
struct connection_buffer *out_head;
|
||||
struct connection_buffer *out_tail;
|
||||
int in_bytes;
|
||||
int out_bytes;
|
||||
int packet_num;
|
||||
int out_packet_num;
|
||||
int last_connect_time;
|
||||
int in_fail_timer;
|
||||
struct mtproto_methods *methods;
|
||||
struct tgl_state *TLS;
|
||||
struct tgl_session *session;
|
||||
struct tgl_dc *dc;
|
||||
void *extra;
|
||||
int ping_ev;
|
||||
int fail_ev;
|
||||
int read_ev;
|
||||
int write_ev;
|
||||
double last_receive_time;
|
||||
void *prpl_data;
|
||||
};
|
||||
|
||||
//extern struct connection *Connections[];
|
||||
|
||||
int tgln_write_out (struct connection *c, const void *data, int len);
|
||||
void tgln_flush_out (struct connection *c);
|
||||
int tgln_read_in (struct connection *c, void *data, int len);
|
||||
int tgln_read_in_lookup (struct connection *c, void *data, int len);
|
||||
|
||||
//void tgln_insert_msg_id (struct tgl_session *S, long long id);
|
||||
|
||||
extern struct tgl_net_methods tgp_conn_methods;
|
||||
|
||||
//void create_all_outbound_connections (void);
|
||||
|
||||
//struct connection *create_connection (const char *host, int port, struct tgl_session *session, struct connection_methods *methods);
|
||||
//struct tgl_dc *tgln_alloc_dc (int id, char *ip, int port);
|
||||
//void tgln_dc_create_session (struct tgl_dc *DC, struct mtproto_methods *methods);
|
||||
struct connection *tgln_create_connection (struct tgl_state *TLS, const char *host, int port, struct tgl_session *session, struct tgl_dc *dc, struct mtproto_methods *methods);
|
||||
|
||||
#define GET_DC(c) (c->session->dc)
|
||||
#endif
|
75
tgp-timers.c
Normal file
75
tgp-timers.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
This file is part of tgl-library
|
||||
|
||||
This library 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 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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 library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Copyright Vitaly Valtman 2013-2014
|
||||
*/
|
||||
#include <tgl.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib.h>
|
||||
#include <eventloop.h>
|
||||
|
||||
struct tgl_timer {
|
||||
struct tgl_state *TLS;
|
||||
void (*cb)(struct tgl_state *, void *);
|
||||
void *arg;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static int timer_alarm (gpointer arg) {
|
||||
struct tgl_timer *t = arg;
|
||||
t->cb (t->TLS, t->arg);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static struct tgl_timer *tgl_timer_alloc (struct tgl_state *TLS, void (*cb)(struct tgl_state *TLS, void *arg), void *arg) {
|
||||
struct tgl_timer *t = malloc (sizeof (*t));
|
||||
t->TLS = TLS;
|
||||
t->cb = cb;
|
||||
t->arg = arg;
|
||||
t->fd = -1;
|
||||
return t;
|
||||
}
|
||||
|
||||
static void tgl_timer_insert (struct tgl_timer *t, double p) {
|
||||
if (p < 0) { p = 0; }
|
||||
if (p < 1) {
|
||||
t->fd = purple_timeout_add (1000 * p, timer_alarm, t);
|
||||
} else {
|
||||
t->fd = purple_timeout_add_seconds (p, timer_alarm, t);
|
||||
}
|
||||
}
|
||||
|
||||
static void tgl_timer_delete (struct tgl_timer *t) {
|
||||
if (t->fd >= 0) {
|
||||
purple_timeout_remove (t->fd);
|
||||
t->fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void tgl_timer_free (struct tgl_timer *t) {
|
||||
if (t->fd >= 0) {
|
||||
tgl_timer_delete (t);
|
||||
}
|
||||
free (t);
|
||||
}
|
||||
|
||||
struct tgl_timer_methods tgp_timers = {
|
||||
.alloc = tgl_timer_alloc,
|
||||
.insert = tgl_timer_insert,
|
||||
.delete = tgl_timer_delete,
|
||||
.free = tgl_timer_free
|
||||
};
|
27
tgp-timers.h
Normal file
27
tgp-timers.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
This file is part of tgl-library
|
||||
|
||||
This library 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 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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 library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
Copyright Vitaly Valtman 2013-2014
|
||||
*/
|
||||
|
||||
#ifndef __TGL_TIMERS_H__
|
||||
#define __TGL_TIMERS_H__
|
||||
|
||||
#include "tgl.h"
|
||||
extern struct tgl_timer_methods tgp_timers;
|
||||
|
||||
#endif
|
Loading…
Add table
Reference in a new issue