diff --git a/purple-plugin/telegram-purple.c b/purple-plugin/telegram-purple.c index 5fd923e..ed651c2 100644 --- a/purple-plugin/telegram-purple.c +++ b/purple-plugin/telegram-purple.c @@ -270,35 +270,34 @@ static void init_dc_settings(PurpleAccount *acc, struct dc *DC) } /** - * This must be implemented. + * Handle a proxy-request of telegram + * + * Request a new proxy connection from purple, and execute tgprpl_login_on_connected + * as callback once the connection is ready */ -static void tgprpl_login(PurpleAccount * acct) +void telegram_on_proxy_request(struct telegram *instance, const char *ip, int port) { - purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); - PurpleConnection *gc = purple_account_get_connection(acct); - char const *username = purple_account_get_username(acct); - _gc = gc; - _pa = acct; - - struct dc DC; - init_dc_settings(acct, &DC); - // TODO: fetch current home directory - // use this as root - struct telegram *tg = telegram_new(&DC, username, "/home/dev-jessie/.telegram"); - telegram_add_state_change_listener(tg, tgprpl_on_state_change); - telegram_restore_session(tg); - - telegram_conn *conn = g_new0(telegram_conn, 1); - conn->tg = tg; - conn->gc = gc; - conn->pa = acct; - purple_connection_set_protocol_data(gc, conn); - tg->extra = conn; - - purple_connection_set_state(gc, PURPLE_CONNECTING); - purple_proxy_connect(gc, acct, DC.ip, DC.port, tgprpl_login_on_connected, tg); + telegram_conn *conn = instance->extra; + purple_proxy_connect (conn->gc, conn->pa, ip, port, tgprpl_login_on_connected, conn->tg); } +/** + * Handle a proxy-close of telegram + * + * Remove all open inputs added to purple + */ +void telegram_on_proxy_close(struct telegram *instance, int fd UU) +{ + telegram_conn *conn = instance->extra; + purple_input_remove (conn->rh); + purple_input_remove (conn->wh); +} + +/** + * A proxy connection was created by purple + * + * Set the proxy to the current telegram-instance, and add callbacks to monitor + */ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_message) { purple_debug_info(PLUGIN_ID, "tgprpl_login_on_connected()\n"); @@ -313,7 +312,8 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa purple_debug_info(PLUGIN_ID, "Connecting to the telegram network...\n"); conn->wh = purple_input_add(fd, PURPLE_INPUT_WRITE, tgprpl_output_cb, tg); conn->rh = purple_input_add(fd, PURPLE_INPUT_READ, tgprpl_input_cb, tg); - telegram_network_connect(tg, fd); + + telegram_set_proxy(tg, fd); // // load all settings: the known network topology, secret keys, logs and configuration file paths // purple_debug_info(PLUGIN_ID, "parse_config()\n"); @@ -364,6 +364,38 @@ void tgprpl_login_on_connected(gpointer *data, gint fd, const gchar *error_messa */ } +/** + * This must be implemented. + */ +static void tgprpl_login(PurpleAccount * acct) +{ + purple_debug_info(PLUGIN_ID, "tgprpl_login()\n"); + PurpleConnection *gc = purple_account_get_connection(acct); + char const *username = purple_account_get_username(acct); + _gc = gc; + _pa = acct; + + struct dc DC; + init_dc_settings(acct, &DC); + + // TODO: fetch current home directory + // use this as root + struct telegram *tg = telegram_new(&DC, username, "/home/dev-jessie/.telegram", + telegram_on_proxy_request, telegram_on_proxy_close); + telegram_add_state_change_listener(tg, tgprpl_on_state_change); + telegram_restore_session(tg); + + telegram_conn *conn = g_new0(telegram_conn, 1); + conn->tg = tg; + conn->gc = gc; + conn->pa = acct; + purple_connection_set_protocol_data(gc, conn); + tg->extra = conn; + + purple_connection_set_state (conn->gc, PURPLE_CONNECTING); + telegram_network_connect(tg); +} + void on_new_message(struct message *M) { purple_debug_info(PLUGIN_ID, "New Message: %s\n", M->message); diff --git a/telegram.c b/telegram.c index d299caa..5f320f1 100755 --- a/telegram.c +++ b/telegram.c @@ -115,7 +115,9 @@ void on_state_change(struct telegram *instance, int state, void *data) } } -struct telegram *telegram_new(struct dc *DC, const char* login, const char *config_path) +struct telegram *telegram_new(struct dc *DC, const char* login, const char *config_path, + void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port), + void (*proxy_close_cb)(struct telegram *instance, int fd)) { struct telegram *this = malloc(sizeof(struct telegram)); this->protocol_data = NULL; @@ -123,6 +125,8 @@ struct telegram *telegram_new(struct dc *DC, const char* login, const char *conf this->auth.DC_list[0] = DC; this->change_state_listeners = NULL; this->bl = talloc0 (sizeof(struct binlog)); + this->proxy_request_cb = proxy_request_cb; + this->proxy_close_cb = proxy_close_cb; this->login = g_strdup(login); this->config_path = g_strdup_printf("%s/%s", config_path, login); @@ -234,18 +238,16 @@ void on_authorized(struct mtproto_connection *c, void* data); /** * Connect to the currently active data center */ -void telegram_network_connect(struct telegram *instance, int fd) +void telegram_network_connect(struct telegram *instance) { logprintf("telegram_network_connect()\n"); if (!instance->auth.DC_list) { logprintf("telegram_network_connect(): cannot connect, restore / init a session first.\n"); assert(0); } - struct dc *DC_working = telegram_get_working_dc(instance); - instance->connection = mtproto_new(DC_working, fd, instance); - instance->connection->on_ready = on_authorized; - instance->connection->on_ready_data = instance; - mtproto_connect(instance->connection); + struct dc *DC_working = telegram_get_working_dc (instance); + assert (instance->proxy_request_cb); + instance->proxy_request_cb (instance, DC_working->ip, DC_working->port); } /** @@ -273,6 +275,13 @@ void on_authorized(struct mtproto_connection *c, void *data) void telegram_read_input (struct telegram *instance) { return try_read(instance->connection->connection); +void telegram_set_proxy(struct telegram *instance, int fd) +{ + struct dc *DC_working = telegram_get_working_dc (instance); + instance->connection = mtproto_new (DC_working, fd, instance); + instance->connection->on_ready = on_authorized; + instance->connection->on_ready_data = instance; + mtproto_connect (instance->connection); } int telegram_write_output (struct telegram *instance) diff --git a/telegram.h b/telegram.h index 66fbfd0..d9dd34e 100644 --- a/telegram.h +++ b/telegram.h @@ -124,15 +124,27 @@ struct telegram { * callbacks */ void (*on_output)(struct telegram *instance); + void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port); + void (*proxy_close_cb)(struct telegram *instance, int fd); void *extra; }; /** - * constructor + * Create a new telegram application + * + * @param DC The initial data center to use + * @param login The phone number to use as login name + * @param config_path The configuration path used to store the content + * @param proxy_request_cb A callback function that delivers a connections to the given hostname + * and port by calling telegram_set_proxy. This is useful for tunelling + * the connection through a proxy server + * @param proxy_close_cb A callback function that is called once the proxy connection is no longer + * needed. This is useful for freeing all used resources */ -struct telegram *telegram_new(struct dc *DC, const char* login, - const char* config_path); +struct telegram *telegram_new(struct dc *DC, const char* login, const char* config_path, + void (*proxy_request_cb)(struct telegram *instance, const char *ip, int port), + void (*proxy_close_cb)(struct telegram *instance, int fd)); /** * Resume the session to @@ -194,7 +206,7 @@ void telegram_change_state(struct telegram *instance, int state, void *data); /** * Connect to the telegram network with the given configuration */ -void telegram_network_connect (struct telegram *instance, int fd); +void telegram_network_connect(struct telegram *instance); int telegram_login (struct telegram *instance); @@ -294,4 +306,11 @@ void set_net_read_cb(ssize_t (*cb)(int fd, void *buff, size_t size)); */ void set_net_write_cb(ssize_t (*cb)(int fd, const void *buff, size_t size)); +/** + * Set the proxy-connection to use + * + * NOTE: you may only call this function from the + */ +void telegram_set_proxy(struct telegram *instance, int fd); + #endif