diff --git a/Makefile.in b/Makefile.in index dfec10c..bf20a9b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -15,8 +15,7 @@ OBJ=objs LIB=libs DIR_LIST=${DEP} ${AUTO} ${EXE} ${OBJ} ${LIB} ${DEP}/auto ${OBJ}/auto - -PLUGIN_OBJECTS=${OBJ}/tgp-net.o ${OBJ}/tgp-timers.o ${OBJ}/msglog.o ${OBJ}/telegram-base.o ${OBJ}/telegram-purple.o ${OBJ}/tgp-2prpl.o ${OBJ}/lodepng.o +PLUGIN_OBJECTS=${OBJ}/tgp-net.o ${OBJ}/tgp-timers.o ${OBJ}/msglog.o ${OBJ}/telegram-base.o ${OBJ}/telegram-purple.o ${OBJ}/tgp-2prpl.o ${OBJ}/tgp-structs.o ${OBJ}/lodepng.o ALL_OBJS=${PLUGIN_OBJECTS} .SUFFIXES: diff --git a/README.md b/README.md index 52dc722..c93485e 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ When encountering a crash or some other bugs, please report it to us, preferably - Support changing own profile picture - Support adding new contacts - Display service messages - + - Works with libpurple proxy settings ## Version 0.4 @@ -45,7 +45,6 @@ The following features are currently planned and will probably be added in the f - File transfers - Geo-locations - Multiple accounts on one client - - Respect libpurple proxy settings (implemented but untested) ## Platform Support diff --git a/imgs/telegram.png b/imgs/telegram.png index b4ae1e5..b368dca 100644 Binary files a/imgs/telegram.png and b/imgs/telegram.png differ diff --git a/imgs/telegram16.png b/imgs/telegram16.png index 91de69d..73ebafc 100644 Binary files a/imgs/telegram16.png and b/imgs/telegram16.png differ diff --git a/imgs/telegram22.png b/imgs/telegram22.png index 709f356..a516801 100644 Binary files a/imgs/telegram22.png and b/imgs/telegram22.png differ diff --git a/imgs/telegram48.png b/imgs/telegram48.png index 3d7263f..aa5f885 100644 Binary files a/imgs/telegram48.png and b/imgs/telegram48.png differ diff --git a/msglog.c b/msglog.c index 42bc597..c0fe878 100644 --- a/msglog.c +++ b/msglog.c @@ -38,15 +38,9 @@ #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"); -} +/* + msglog.c: Convenience methods for logging to libpurple log + */ void log_level_printf (const char* format, va_list ap, int level, char *color) { char buffer[256]; diff --git a/msglog.h b/msglog.h index 43fe8f8..bb9f256 100644 --- a/msglog.h +++ b/msglog.h @@ -19,8 +19,6 @@ */ #include -void hexdump (int *in_ptr, int *in_end); - void debug(const char* format, ...); void info(const char* format, ...); void warning(const char* format, ...); diff --git a/telegram-base.c b/telegram-base.c index b5edd69..a2ccca1 100644 --- a/telegram-base.c +++ b/telegram-base.c @@ -35,6 +35,7 @@ #include #include #include +#include "tgp-structs.h" #include "lodepng.h" #define DC_SERIALIZED_MAGIC 0x868aa81d @@ -164,6 +165,15 @@ void read_dc (struct tgl_state *TLS, int auth_file_fd, int id, unsigned ver) { bl_do_dc_signed (TLS, id); } +int error_if_val_false (struct tgl_state *TLS, int val, const char *msg) { + if (!val) { + connection_data *conn = TLS->ev_base; + purple_connection_error_reason (conn->gc, PURPLE_CONNECTION_ERROR_AUTHENTICATION_FAILED, msg); + return 1; + } + return 0; +} + 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); @@ -226,8 +236,9 @@ void read_auth_file (struct tgl_state *TLS) { 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); + if (!error_if_val_false(TLS, success, "Authentication Export failed.")) { + telegram_export_authorization (TLS); + } } void telegram_export_authorization (struct tgl_state *TLS) { @@ -262,21 +273,21 @@ static void code_auth_receive_result (struct tgl_state *TLS, void *extra, int su void request_code_entered (gpointer data, const gchar *code) { struct tgl_state *TLS = data; - telegram_conn *conn = TLS->ev_base; + connection_data *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; + connection_data *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); + connection_data *conn = purple_connection_get_protocol_data(gc); struct tgl_state *TLS = conn->TLS; char const *username = purple_account_get_username(conn->pa); @@ -293,7 +304,7 @@ static void request_name_code_entered (PurpleConnection* gc, PurpleRequestFields static void request_code (struct tgl_state *TLS) { debug ("Client is not registered, registering...\n"); - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; int compat = purple_account_get_bool (tg_get_acc(TLS), "compat-verification", 0); if (compat || ! purple_request_input (conn->gc, "Telegram Code", "Enter Telegram Code", @@ -315,7 +326,7 @@ static void request_code (struct tgl_state *TLS) { static void request_name_and_code (struct tgl_state *TLS) { debug ("Phone is not registered, registering...\n"); - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; PurpleRequestFields* fields = purple_request_fields_new(); PurpleRequestField* field = 0; @@ -342,14 +353,14 @@ static void request_name_and_code (struct tgl_state *TLS) { } 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); + connection_data *conn = TLS->ev_base; + if (!error_if_val_false (TLS, success, "Invalid or non-existing phone number.")) { + conn->hash = strdup (mhash); + if (registered) { + request_code (TLS); + } else { + request_name_and_code (TLS); + } } } @@ -358,7 +369,7 @@ static void telegram_send_sms (struct tgl_state *TLS) { telegram_export_authorization (TLS); return; } - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; char const *username = purple_account_get_username(conn->pa); tgl_do_send_code (TLS, username, sign_in_callback, 0); } @@ -395,7 +406,7 @@ void telegram_login (struct tgl_state *TLS) { PurpleConversation *chat_show (PurpleConnection *gc, int id) { debug ("show chat"); - telegram_conn *conn = purple_connection_get_protocol_data(gc); + connection_data *conn = purple_connection_get_protocol_data(gc); PurpleConversation *convo = purple_find_chat(gc, id); if (! convo) { @@ -411,17 +422,20 @@ PurpleConversation *chat_show (PurpleConnection *gc, int id) { } int chat_add_message (struct tgl_state *TLS, struct tgl_message *M, char *text) { - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; if (chat_show (conn->gc, tgl_get_peer_id (M->to_id))) { p2tgl_got_chat_in(TLS, M->to_id, M->from_id, text ? text : M->message, M->service ? PURPLE_MESSAGE_SYSTEM : PURPLE_MESSAGE_RECV, M->date); + + pending_reads_add (conn->pending_reads, M->to_id); + if (p2tgl_status_is_present(purple_account_get_active_status(conn->pa))) { + pending_reads_send_all (conn->pending_reads, conn->TLS); + } return 1; } else { // add message once the chat was initialised - struct message_text *mt = malloc (sizeof (*mt)); - mt->M = M; - mt->text = text ? g_strdup (text) : text; + struct message_text *mt = message_text_init (M, text); g_queue_push_tail (conn->new_messages, mt); return 0; } @@ -442,6 +456,9 @@ void chat_add_all_users (PurpleConversation *pc, struct tgl_chat *chat) { } } +/** + * This function generates a png image to visulize the sha1 key from an encrypted chat. + */ int generate_ident_icon (unsigned char* sha1_key) { int colors[4] = { @@ -490,4 +507,4 @@ int generate_ident_icon (unsigned char* sha1_key) g_free(image); g_free(png); return imgStoreId; -} \ No newline at end of file +} diff --git a/telegram-base.h b/telegram-base.h index 4b3d16d..dbe1c33 100644 --- a/telegram-base.h +++ b/telegram-base.h @@ -19,6 +19,9 @@ */ #ifndef __TELEGRAM_BASE_H__ #define __TELEGRAM_BASE_H__ + +#include "telegram-purple.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); @@ -30,4 +33,5 @@ int chat_add_message (struct tgl_state *TLS, struct tgl_message *M, char *text); void chat_add_all_users (PurpleConversation *pc, struct tgl_chat *chat); void request_code_entered (gpointer data, const gchar *code); int generate_ident_icon(unsigned char* sha1_key); + #endif diff --git a/telegram-purple.c b/telegram-purple.c index 6f31c07..96e523f 100644 --- a/telegram-purple.c +++ b/telegram-purple.c @@ -51,6 +51,7 @@ #include "request.h" #include +#include "tgp-structs.h" #include "tgp-2prpl.h" #include "tgp-net.h" #include "tgp-timers.h" @@ -65,8 +66,8 @@ const char *pk_path = "/etc/telegram-purple/server.pub"; void tgprpl_login_on_connected(); void on_user_get_info (struct tgl_state *TLS, void *show_info, int success, struct tgl_user *U); -static telegram_conn *get_conn_from_buddy (PurpleBuddy *buddy) { - telegram_conn *c = purple_connection_get_protocol_data ( +static connection_data *get_conn_from_buddy (PurpleBuddy *buddy) { + connection_data *c = purple_connection_get_protocol_data ( purple_account_get_connection (purple_buddy_get_account (buddy))); return c; } @@ -181,12 +182,17 @@ static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) static int our_msg (struct tgl_state *TLS, struct tgl_message *M) { //return tgl_get_peer_id(M->from_id) == TLS->our_id; + //return M->out; + return (M->flags & FLAG_SESSION_OUTBOUND) != 0; +} + +static int out_msg (struct tgl_state *TLS, struct tgl_message *M) { return M->out; } static gboolean queries_timerfunc (gpointer data) { debug ("queries_timerfunc()\n"); - telegram_conn *conn = data; + connection_data *conn = data; if (conn->updated) { conn->updated = 0; @@ -230,25 +236,28 @@ struct tgl_update_callback tgp_callback = { }; void on_message_load_photo (struct tgl_state *TLS, void *extra, int success, char *filename) { + connection_data *conn = TLS->ev_base; + gchar *data = NULL; size_t len; GError *err = NULL; g_file_get_contents (filename, &data, &len, &err); int imgStoreId = purple_imgstore_add_with_id (g_memdup(data, (guint)len), len, NULL); - - char *image = format_img_full(imgStoreId); + used_images_add (conn, imgStoreId); + + char *image = format_img_full (imgStoreId); struct tgl_message *M = extra; switch (tgl_get_peer_type (M->to_id)) { case TGL_PEER_CHAT: debug ("PEER_CHAT\n"); - if (! our_msg(TLS, M)) { + if (!our_msg(TLS, M)) { chat_add_message (TLS, M, image); } break; case TGL_PEER_USER: debug ("PEER_USER\n"); - if (our_msg(TLS, M)) { + if (out_msg(TLS, M)) { p2tgl_got_im (TLS, M->to_id, image, PURPLE_MESSAGE_SEND | PURPLE_MESSAGE_IMAGES, M->date); } else { p2tgl_got_im (TLS, M->from_id, image, PURPLE_MESSAGE_RECV | PURPLE_MESSAGE_IMAGES, M->date); @@ -267,13 +276,13 @@ void on_message_load_photo (struct tgl_state *TLS, void *extra, int success, cha } g_free (image); - telegram_conn *conn = TLS->ev_base; + conn = TLS->ev_base; conn->updated = 1; } static void update_message_received (struct tgl_state *TLS, struct tgl_message *M) { debug ("received message\n"); - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; conn->updated = 1; if (M->service) { @@ -316,7 +325,7 @@ static void update_message_received (struct tgl_state *TLS, struct tgl_message * switch (tgl_get_peer_type (M->to_id)) { case TGL_PEER_CHAT: debug ("PEER_CHAT\n"); - if (! our_msg(TLS, M)) { + if (!our_msg(TLS, M)) { chat_add_message (TLS, M, text); } break; @@ -326,8 +335,17 @@ static void update_message_received (struct tgl_state *TLS, struct tgl_message * // p2tgl_got_im (TLS, M->to_id, text, PURPLE_MESSAGE_SEND, M->date); // :TODO: figure out how to add messages from different devices to history - if (! our_msg(TLS, M)) { - p2tgl_got_im (TLS, M->from_id, text, PURPLE_MESSAGE_RECV, M->date); + if (!our_msg(TLS, M)) { + if (out_msg(TLS, M)) { + p2tgl_got_im (TLS, M->to_id, text, PURPLE_MESSAGE_SEND, M->date); + } else { + p2tgl_got_im (TLS, M->from_id, text, PURPLE_MESSAGE_RECV, M->date); + + pending_reads_add (conn->pending_reads, M->from_id); + if (p2tgl_status_is_present(purple_account_get_active_status(conn->pa))) { + pending_reads_send_all (conn->pending_reads, conn->TLS); + } + } } break; @@ -362,9 +380,6 @@ static void update_user_handler (struct tgl_state *TLS, struct tgl_user *user, u p2tgl_prpl_got_user_status (TLS, user->id, &user->status); p2tgl_buddy_update (TLS, (tgl_peer_t *)user, flags); } - if (flags & (TGL_UPDATE_NAME | TGL_UPDATE_REAL_NAME | TGL_UPDATE_USERNAME) && buddy) { - p2tgl_blist_alias_buddy (buddy, user); - } if (flags & TGL_UPDATE_PHOTO) { tgl_do_get_user_info (TLS, user->id, 0, on_user_get_info, 0); } @@ -449,13 +464,15 @@ static void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success, struct tgl_user *U = dld->data; warning ("Can not load userpic for user %s %s\n", U->first_name, U->last_name); } - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; gchar *data = NULL; size_t len; GError *err = NULL; g_file_get_contents (filename, &data, &len, &err); + int imgStoreId = purple_imgstore_add_with_id (g_memdup(data, (guint)len), len, NULL); + used_images_add (conn, imgStoreId); struct download_desc *dld = extra; struct tgl_user *U = dld->data; @@ -482,7 +499,7 @@ static void on_userpic_loaded (struct tgl_state *TLS, void *extra, int success, purple_notify_userinfo (conn->gc, who, info, NULL, NULL); g_free (profile_image); } - purple_buddy_icons_set_for_user(conn->pa, who, g_memdup(data, (guint)len), len, NULL); + purple_buddy_icons_set_for_user(conn->pa, who, data, len, NULL); g_free(who); } @@ -507,7 +524,7 @@ void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct t assert (success); debug ("on_chat_joined(%d)\n", tgl_get_peer_id (C->id)); - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; PurpleConversation *conv; if (!(conv = purple_find_chat(conn->gc, tgl_get_peer_id(C->id)))) { @@ -534,13 +551,9 @@ void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct t g_free (name); } -// This function generates a png image to visulize the sha1 key from an encrypted chat. - - - void on_ready (struct tgl_state *TLS) { debug ("on_ready().\n"); - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; purple_connection_set_state(conn->gc, PURPLE_CONNECTED); purple_connection_set_display_name(conn->gc, purple_account_get_username(conn->pa)); @@ -585,16 +598,25 @@ static GList *tgprpl_status_types (PurpleAccount * acct) { debug ("tgprpl_status_types()\n"); GList *types = NULL; PurpleStatusType *type; - type = purple_status_type_new_with_attrs (PURPLE_STATUS_AVAILABLE, NULL, NULL, - 1, 1, 0, "last online", "last online", purple_value_new (PURPLE_TYPE_STRING), NULL); + + type = purple_status_type_new_full(PURPLE_STATUS_AVAILABLE, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_prepend (types, type); - type = purple_status_type_new_with_attrs (PURPLE_STATUS_MOBILE, NULL, NULL, 1, - 1, 0, "last online", "last online", purple_value_new (PURPLE_TYPE_STRING), NULL); + type = purple_status_type_new_full(PURPLE_STATUS_MOBILE, NULL, NULL, FALSE, TRUE, FALSE); + types = g_list_prepend (types, type); + + type = purple_status_type_new_full(PURPLE_STATUS_OFFLINE, NULL, NULL, FALSE, TRUE, FALSE); types = g_list_prepend (types, type); - type = purple_status_type_new (PURPLE_STATUS_OFFLINE, NULL, NULL, 1); - types = g_list_append (types, type); + /* + The states below are only registered internally so that we get notified about + state changes to away and unavailable. This is useful for deciding when to send + No other peer should ever have those states. + */ + type = purple_status_type_new_full(PURPLE_STATUS_AWAY, NULL, NULL, FALSE, TRUE, FALSE); + types = g_list_prepend (types, type); + type = purple_status_type_new_full(PURPLE_STATUS_UNAVAILABLE, NULL, NULL, FALSE, TRUE, FALSE); + types = g_list_prepend (types, type); return g_list_reverse (types); } @@ -637,12 +659,7 @@ static void tgprpl_login (PurpleAccount * acct) { // create handle to store additional info for libpurple in // the new telegram instance - telegram_conn *conn = g_new0(telegram_conn, 1); - conn->TLS = TLS; - conn->gc = gc; - conn->pa = acct; - conn->new_messages = g_queue_new (); - conn->joining_chats = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + connection_data *conn = connection_data_init (TLS, gc, acct); purple_connection_set_protocol_data (gc, conn); tgl_set_ev_base (TLS, conn); @@ -659,15 +676,16 @@ static void tgprpl_login (PurpleAccount * acct) { static void tgprpl_close (PurpleConnection * gc) { debug ("tgprpl_close()\n"); - telegram_conn *conn = purple_connection_get_protocol_data(gc); - purple_timeout_remove(conn->timer); - tgl_free_all (conn->TLS); + connection_data *conn = purple_connection_get_protocol_data (gc); + purple_timeout_remove (conn->timer); + + connection_data_free (conn); } static int tgprpl_send_im (PurpleConnection * gc, const char *who, const char *message, PurpleMessageFlags flags) { debug ("tgprpl_send_im()\n"); - telegram_conn *conn = purple_connection_get_protocol_data(gc); + connection_data *conn = purple_connection_get_protocol_data(gc); PurpleAccount *pa = conn->pa; // this is part of a workaround to support clients without @@ -698,7 +716,7 @@ static int tgprpl_send_im (PurpleConnection * gc, const char *who, const char *m static unsigned int tgprpl_send_typing (PurpleConnection * gc, const char *who, PurpleTypingState typing) { debug ("tgprpl_send_typing()\n"); int id = atoi (who); - telegram_conn *conn = purple_connection_get_protocol_data(gc); + connection_data *conn = purple_connection_get_protocol_data(gc); tgl_peer_t *U = tgl_peer_get (conn->TLS, TGL_MK_USER (id)); if (U) { if (typing == PURPLE_TYPING) { @@ -712,41 +730,42 @@ static unsigned int tgprpl_send_typing (PurpleConnection * gc, const char *who, static void tgprpl_get_info (PurpleConnection * gc, const char *username) { debug ("tgprpl_get_info()\n"); - telegram_conn *conn = purple_connection_get_protocol_data(gc); + connection_data *conn = purple_connection_get_protocol_data(gc); tgl_peer_id_t u = TGL_MK_USER(atoi(username)); tgl_do_get_user_info (conn->TLS, u, 0, on_user_get_info, (void *)1l); } static void tgprpl_set_status (PurpleAccount * acct, PurpleStatus * status) { - debug ("tgprpl_set_status()\n"); + debug ("tgprpl_set_status(%s)\n", purple_status_get_name (status)); + debug ("tgprpl_set_status(currstatus=%s)\n", purple_status_get_name(purple_account_get_active_status(acct))); + + PurpleConnection *gc = purple_account_get_connection(acct); + if (!gc) { return; } + connection_data *conn = purple_connection_get_protocol_data (gc); + + if (p2tgl_status_is_present(status)) { + pending_reads_send_all (conn->pending_reads, conn->TLS); + } } static void tgprpl_add_buddy (PurpleConnection * gc, PurpleBuddy * buddy, PurpleGroup * group) { - telegram_conn *conn = purple_connection_get_protocol_data(gc); + connection_data *conn = purple_connection_get_protocol_data(gc); const char* first = buddy->alias ? buddy->alias : ""; tgl_do_add_contact (conn->TLS, buddy->name, (int)strlen (buddy->name), first, (int)strlen (first), "", 0, 0, on_contact_added, buddy); } -static void tgprpl_add_buddies (PurpleConnection * gc, GList * buddies, GList * groups) { - debug ("tgprpl_add_buddies()\n"); -} - static void tgprpl_remove_buddy (PurpleConnection * gc, PurpleBuddy * buddy, PurpleGroup * group) { debug ("tgprpl_remove_buddy()\n"); if (!buddy) { return; } - telegram_conn *conn = purple_connection_get_protocol_data (gc); + connection_data *conn = purple_connection_get_protocol_data (gc); struct tgl_user *user = purple_buddy_get_protocol_data (buddy); if (!user) { warning ("cannot remove buddy '%s', no protocol data found\n", buddy->name); return; } tgl_do_del_contact (conn->TLS, user->id, NULL, NULL); } -static void tgprpl_remove_buddies (PurpleConnection * gc, GList * buddies, GList * groups){ - debug ("tgprpl_remove_buddies()\n"); -} - static void tgprpl_add_deny (PurpleConnection * gc, const char *name){ debug ("tgprpl_add_deny()\n"); } @@ -758,7 +777,7 @@ static void tgprpl_rem_deny (PurpleConnection * gc, const char *name){ static void tgprpl_chat_join (PurpleConnection * gc, GHashTable * data) { debug ("tgprpl_chat_join()\n"); - telegram_conn *conn = purple_connection_get_protocol_data (gc); + connection_data *conn = purple_connection_get_protocol_data (gc); const char *groupname = g_hash_table_lookup (data, "subject"); char *id = g_hash_table_lookup(data, "id"); @@ -795,7 +814,7 @@ static GHashTable *tgprpl_chat_info_deflt (PurpleConnection * gc, const char *ch static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *message, const char *name) { debug ("tgprpl_chat_invite()\n"); - telegram_conn *conn = purple_connection_get_protocol_data (gc); + connection_data *conn = purple_connection_get_protocol_data (gc); tgl_peer_t *chat = tgl_peer_get(conn->TLS, TGL_MK_CHAT (id)); tgl_peer_t *user = tgl_peer_get(conn->TLS, TGL_MK_USER (atoi(name))); @@ -809,14 +828,20 @@ static void tgprpl_chat_invite (PurpleConnection * gc, int id, const char *messa static int tgprpl_send_chat (PurpleConnection * gc, int id, const char *message, PurpleMessageFlags flags) { debug ("tgprpl_send_chat()\n"); - telegram_conn *conn = purple_connection_get_protocol_data (gc); + connection_data *conn = purple_connection_get_protocol_data (gc); gchar *raw = purple_unescape_html(message); tgl_do_send_message (conn->TLS, TGL_MK_CHAT(id), raw, (int)strlen (raw), 0, 0); g_free (raw); + /* Pidgin won't display the written message if we don't call this, Adium will display it twice + if we call it, so we don't do it for the adium Plugin. + TODO: there has to be a better way to do this, figure out how. + */ +#ifndef __ADIUM_ p2tgl_got_chat_in(conn->TLS, TGL_MK_CHAT(id), TGL_MK_USER(conn->TLS->our_id), message, - PURPLE_MESSAGE_RECV, time(NULL)); + PURPLE_MESSAGE_RECV, time(NULL)); +#endif return 1; } @@ -835,7 +860,7 @@ static void tgprpl_convo_closed (PurpleConnection * gc, const char *who){ static void tgprpl_set_buddy_icon (PurpleConnection * gc, PurpleStoredImage * img) { debug ("tgprpl_set_buddy_icon()\n"); - telegram_conn *conn = purple_connection_get_protocol_data (gc); + connection_data *conn = purple_connection_get_protocol_data (gc); if (purple_imgstore_get_filename (img)) { char* filename = g_strdup_printf ("%s/icons/%s", purple_user_dir(), purple_imgstore_get_filename (img)); debug (filename); @@ -906,9 +931,9 @@ static PurplePluginProtocolInfo prpl_info = { NULL, // set_idle NULL, // change_passwd tgprpl_add_buddy, - tgprpl_add_buddies, + NULL, // add_buddies tgprpl_remove_buddy, - tgprpl_remove_buddies, + NULL, // remove_buddies NULL, // add_permit tgprpl_add_deny, NULL, // rem_permit @@ -964,8 +989,7 @@ static PurplePluginProtocolInfo prpl_info = { static void tgprpl_init (PurplePlugin *plugin) { PurpleAccountOption *opt; - opt = purple_account_option_bool_new("Compatibility Mode (read SMS code from settings)", - "compat-verification", 0); + opt = purple_account_option_bool_new("Fallback SMS verification", "compat-verification", 0); prpl_info.protocol_options = g_list_append(prpl_info.protocol_options, opt); _telegram_protocol = plugin; diff --git a/telegram-purple.h b/telegram-purple.h index 3b36565..af0a216 100644 --- a/telegram-purple.h +++ b/telegram-purple.h @@ -28,7 +28,6 @@ #define TG_VERSION "0.5" #define TG_BUILD "10" -#include #include #include #include @@ -38,28 +37,6 @@ #define TGP_APP_HASH "99428c722d0ed59b9cd844e4577cb4bb" #define TGP_APP_ID 16154 -typedef struct { - struct tgl_state *TLS; - char *hash; - PurpleAccount *pa; - PurpleConnection *gc; - int updated; - GQueue *new_messages; - GHashTable *joining_chats; - guint timer; - int in_fallback_chat; -} telegram_conn; - -struct download_desc { - int type; - void *data; -}; - -struct message_text { - struct tgl_message *M; - char *text; -}; - void on_chat_get_info (struct tgl_state *TLS, void *extra, int success, struct tgl_chat *C); void on_ready (struct tgl_state *TLS); extern const char *pk_path; diff --git a/tgl b/tgl index d78ebeb..cebe282 160000 --- a/tgl +++ b/tgl @@ -1 +1 @@ -Subproject commit d78ebeb6c61b63755052ef6d0f08113396173657 +Subproject commit cebe2822a2620961692ac45b0ea2ee99d396c5fb diff --git a/tgp-2prpl.c b/tgp-2prpl.c index e85be99..e6e4191 100644 --- a/tgp-2prpl.c +++ b/tgp-2prpl.c @@ -19,12 +19,17 @@ */ #include "telegram-purple.h" #include "tgp-2prpl.h" +#include "tgp-structs.h" #include #include #include #include +/* + tgp-2prpl.c: Libpurple functions that can be called with tgl data types + */ + static void sanitize_alias(char *buffer) { size_t len = strlen(buffer); gchar *curr; @@ -56,11 +61,11 @@ static int user_get_alias (tgl_peer_t *user, char *buffer, int maxlen) { } PurpleAccount *tg_get_acc (struct tgl_state *TLS) { - return (PurpleAccount *) ((telegram_conn *)TLS->ev_base)->pa; + return (PurpleAccount *) ((connection_data *)TLS->ev_base)->pa; } PurpleConnection *tg_get_conn (struct tgl_state *TLS) { - return (PurpleConnection *) ((telegram_conn *)TLS->ev_base)->gc; + return (PurpleConnection *) ((connection_data *)TLS->ev_base)->gc; } static char *peer_strdup_id(tgl_peer_id_t user) { @@ -85,6 +90,12 @@ char *p2tgl_strdup_alias(tgl_peer_t *user) { return g_alias; } +int p2tgl_status_is_present (PurpleStatus *status) +{ + const char *name = purple_status_get_id (status); + return !(strcmp (name, "unavailable") == 0 || strcmp (name, "away") == 0); +} + static PurpleChat *blist_find_chat_by_hasht_cond(PurpleConnection *gc, int (*fn)(GHashTable *hasht, void *data), void *data) { PurpleAccount *account = purple_connection_get_account(gc); @@ -105,12 +116,16 @@ static PurpleChat *blist_find_chat_by_hasht_cond(PurpleConnection *gc, } static int hasht_cmp_id(GHashTable *hasht, void *data) { - return !strcmp(g_hash_table_lookup(hasht, "id"), *((char **)data)); + gpointer id = g_hash_table_lookup(hasht, "id"); + if (!id || !data) { + return 0; + } + return !strcmp(id, ((char *)data)); } PurpleConversation *p2tgl_got_joined_chat (struct tgl_state *TLS, struct tgl_chat *chat) { - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; gchar *alias = p2tgl_strdup_alias((tgl_peer_t *)chat); PurpleConversation *conv = serv_got_joined_chat(conn->gc, tgl_get_peer_id(chat->id), alias); @@ -181,7 +196,7 @@ PurpleBuddy *p2tgl_buddy_update (struct tgl_state *TLS, tgl_peer_t *user, unsign if (!b) { b = p2tgl_buddy_new (TLS, user); } - if (flags & TGL_UPDATE_NAME) { + if (flags & (TGL_UPDATE_NAME | TGL_UPDATE_REAL_NAME | TGL_UPDATE_USERNAME)) { debug ("Update username for id%d (name %s %s)\n", tgl_get_peer_id (user->id), user->user.first_name, user->user.last_name); char *alias = p2tgl_strdup_alias (user); purple_blist_alias_buddy(b, alias); @@ -248,7 +263,7 @@ PurpleChat *p2tgl_chat_new (struct tgl_state *TLS, struct tgl_chat *chat) { PurpleChat *p2tgl_chat_find (struct tgl_state *TLS, tgl_peer_id_t id) { char *name = peer_strdup_id(id); - PurpleChat *c = blist_find_chat_by_hasht_cond(tg_get_conn(TLS), hasht_cmp_id, &name); + PurpleChat *c = blist_find_chat_by_hasht_cond(tg_get_conn(TLS), hasht_cmp_id, name); g_free(name); return c; } diff --git a/tgp-2prpl.h b/tgp-2prpl.h index 319281a..77f04a5 100644 --- a/tgp-2prpl.h +++ b/tgp-2prpl.h @@ -36,6 +36,7 @@ tgl_peer_t *p2tgl_get_peer (tgl_peer_id_t peer); tgl_peer_t *p2tgl_get_peer_by_id (int id); char *p2tgl_strdup_alias(tgl_peer_t *user); +int p2tgl_status_is_present (PurpleStatus *status); PurpleConversation *p2tgl_got_joined_chat (struct tgl_state *TLS, struct tgl_chat *chat); void p2tgl_got_chat_invite (PurpleConnection *gc, tgl_peer_t *chat, tgl_peer_id_t inviter, const char *message); diff --git a/tgp-net.c b/tgp-net.c index 1117fd2..dc49408 100644 --- a/tgp-net.c +++ b/tgp-net.c @@ -42,6 +42,7 @@ #include #include "tgp-net.h" +#include "tgp-structs.h" #include #include @@ -83,6 +84,7 @@ static int ping_alarm (gpointer arg) { static void stop_ping_timer (struct connection *c) { purple_timeout_remove (c->ping_ev); + c->ping_ev = -1; } static void start_ping_timer (struct connection *c) { @@ -333,7 +335,7 @@ struct connection *tgln_create_connection (struct tgl_state *TLS, const char *ho c->conn_timeout = MIN_EXP_TIMEOUT; - telegram_conn *conn = TLS->ev_base; + connection_data *conn = TLS->ev_base; c->prpl_data = purple_proxy_connect (conn->gc, conn->pa, host, port, net_on_connected, c); return c; @@ -346,8 +348,9 @@ static void restart_connection (struct connection *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); + connection_data *conn = TLS->ev_base; + purple_connection_error_reason (conn->gc, PURPLE_CONNECTION_ERROR_NETWORK_ERROR, "Lost connection with server"); + // 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) { @@ -383,7 +386,7 @@ static void fail_connection (struct connection *c) { c->out_bytes = c->in_bytes = 0; if (c->state == conn_ready) { - telegram_conn *conn = TLS->ev_base; + connection_data *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? @@ -457,7 +460,9 @@ static void try_rpc_read (struct connection *c) { len *= 4; int op; assert (tgln_read_in_lookup (c, &op, 4) == 4); - c->methods->execute (TLS, c, op, len); + if (c->methods->execute (TLS, c, op, len) < 0) { + return; + } } } @@ -593,6 +598,7 @@ static void tgln_free (struct connection *c) { purple_input_remove (c->write_ev); } + if (c->fd >= 0) { close (c->fd); } c->fd = -1; } diff --git a/tgp-structs.c b/tgp-structs.c new file mode 100644 index 0000000..138e777 --- /dev/null +++ b/tgp-structs.c @@ -0,0 +1,122 @@ +/* + This file is part of telegram-purple + + 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 + + Copyright Matthias Jentsch 2014 + */ + +#include "tgp-structs.h" +#include "purple.h" +#include "msglog.h" + +#include +#include + +/* + tgp-structs.c: Structs that are only used internally by the protocol plugin + */ + +void pending_reads_free_cb (gpointer data) +{ + free (data); +} + +static void pending_reads_cb (struct tgl_state *TLS, void *extra, int success) +{ + debug ("ack state: %d", success); +} + +static gint pending_reads_compare (gconstpointer a, gconstpointer b) +{ + return !memcmp ((tgl_peer_id_t *)a, (tgl_peer_id_t *)b, sizeof(tgl_peer_id_t)); +} + +void pending_reads_send_all (GQueue *queue, struct tgl_state *TLS) +{ + debug ("send all pending ack"); + + tgl_peer_id_t *pending; + + while ((pending = (tgl_peer_id_t*) g_queue_pop_head(queue))) { + tgl_do_mark_read (TLS, *pending, pending_reads_cb, queue); + debug ("tgl_do_mark_read (%d)", pending->id); + free (pending); + } +} + +void pending_reads_add (GQueue *queue, tgl_peer_id_t id) +{ + tgl_peer_id_t *copy = malloc (sizeof(tgl_peer_id_t)); + *copy = id; + if (! g_queue_find_custom (queue, copy, pending_reads_compare)) { + g_queue_push_tail (queue, copy); + } +} + +struct message_text *message_text_init (struct tgl_message *M, gchar *text) +{ + struct message_text *mt = malloc (sizeof (struct message_text)); + mt->M = M; + mt->text = text ? g_strdup (text) : text; + return mt; +} + +void message_text_free (gpointer data) +{ + struct message_text *mt = (struct message_text*)data; + if (mt->text) { + g_free (mt->text); + } + free (mt); +} + +static void used_image_free (gpointer data) +{ + int id = GPOINTER_TO_INT(data); + purple_imgstore_unref_by_id (id); + debug ("used_image: unref %d", id); +} + +void used_images_add (connection_data *data, gint imgid) +{ + data->used_images = g_list_append (data->used_images, GINT_TO_POINTER(imgid)); + debug ("used_image: add %d", imgid); +} + +connection_data *connection_data_init (struct tgl_state *TLS, PurpleConnection *gc, PurpleAccount *pa) +{ + connection_data *conn = g_new0 (connection_data, 1); + conn->TLS = TLS; + conn->gc = gc; + conn->pa = pa; + conn->new_messages = g_queue_new (); + conn->pending_reads = g_queue_new (); + conn->joining_chats = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + return conn; +} + +void *connection_data_free (connection_data *conn) +{ + purple_timeout_remove(conn->timer); + g_queue_free_full (conn->pending_reads, pending_reads_free_cb); + g_queue_free_full (conn->new_messages, message_text_free); + g_hash_table_destroy (conn->joining_chats); + g_list_free_full (conn->used_images, used_image_free); + tgl_free_all (conn->TLS); + free (conn); + return NULL; +} + diff --git a/tgp-structs.h b/tgp-structs.h new file mode 100644 index 0000000..fe0dc0b --- /dev/null +++ b/tgp-structs.h @@ -0,0 +1,64 @@ +/* + This file is part of telegram-purple + + 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 + + Copyright Matthias Jentsch 2014 + */ + +#ifndef __telegram_adium__tgp_data__ +#define __telegram_adium__tgp_data__ + +#include "purple.h" + +#include +#include + +typedef struct { + struct tgl_state *TLS; + char *hash; + PurpleAccount *pa; + PurpleConnection *gc; + int updated; + GQueue *new_messages; + GQueue *pending_reads; + GList *used_images; + GHashTable *joining_chats; + guint timer; + int in_fallback_chat; +} connection_data; + +struct download_desc { + int type; + void *data; +}; + +struct message_text { + struct tgl_message *M; + char *text; +}; + +void pending_reads_send_all (GQueue *queue, struct tgl_state *TLS); +void pending_reads_add (GQueue *queue, tgl_peer_id_t id); + +struct message_text *message_text_init (struct tgl_message *M, gchar *text); +void message_text_free (gpointer data); + +void used_images_add (connection_data *data, gint imgid); + +void *connection_data_free (connection_data *conn); +connection_data *connection_data_init (struct tgl_state *TLS, PurpleConnection *gc, PurpleAccount *pa); + +#endif