tgl_peer_t *find_peer_by_name (struct tgl_state *TLS, const char *who) { tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER(atoi (who))); if (peer) { return peer; } peer = tgl_peer_get (TLS, TGL_MK_CHAT(atoi(who))); if (peer) { return peer; } peer = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT(atoi(who))); if (peer) { return peer; } return NULL; }
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); 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))); if (! chat || ! user) { purple_notify_error (_telegram_protocol, "Not found", "Cannot invite buddy to chat.", "Specified user is not existing."); return; } tgl_do_add_user_to_chat (conn->TLS, chat->id, user->id, 0, NULL, NULL); }
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); PurpleAccount *pa = conn->pa; // this is part of a workaround to support clients without // the request API (request.h), see telegram-base.c:request_code() if (conn->in_fallback_chat) { request_code_entered (conn->TLS, message); conn->in_fallback_chat = 0; return 1; } PurpleBuddy *b = purple_find_buddy (pa, who); if (!b) { warning ("Buddy %s not found, cannot send IM\n", who); return -1; } tgl_peer_t *peer = tgl_peer_get(conn->TLS, TGL_MK_USER(atoi (who))); if (!peer) { warning ("Protocol data tgl_peer_t for %s not found, cannot send IM\n", who); return -1; } gchar *raw = purple_unescape_html(message); tgl_do_send_message (conn->TLS, peer->id, raw, (int)strlen (raw), 0, 0); g_free(raw); return 1; }
void bl_do_chat_del_user (struct tgl_state *TLS, tgl_peer_id_t id, int version, int user) /* {{{ */ { tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P || !(P->flags & TGLPF_CREATED)) { return; } struct tgl_chat *C = &P->chat; if (C->user_list_version >= version || !C->user_list_version) { return; } int i; for (i = 0; i < C->user_list_size; i++) { if (C->user_list[i].user_id == user) { struct tgl_chat_user t; t = C->user_list[i]; C->user_list[i] = C->user_list[C->user_list_size - 1]; C->user_list[C->user_list_size - 1] = t; } } if (C->user_list[C->user_list_size - 1].user_id != user) { return; } assert (C->user_list[C->user_list_size - 1].user_id == user); C->user_list_size --; C->user_list = trealloc (C->user_list, 12 * C->user_list_size + 12, 12 * C->user_list_size); C->user_list_version = version; if (TLS->callback.chat_update) { TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS); } }
void bl_do_chat_add_user (struct tgl_state *TLS, tgl_peer_id_t id, int version, int user, int inviter, int date) /* {{{ */ { tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P || !(P->flags & TGLPF_CREATED)) { return; } struct tgl_chat *C = &P->chat; if (C->user_list_version >= version || !C->user_list_version) { return; } int i; for (i = 0; i < C->user_list_size; i++) { if (C->user_list[i].user_id == user) { return; } } C->user_list_size ++; C->user_list = trealloc (C->user_list, 12 * C->user_list_size - 12, 12 * C->user_list_size); C->user_list[C->user_list_size - 1].user_id = user; C->user_list[C->user_list_size - 1].inviter_id = inviter; C->user_list[C->user_list_size - 1].date = date; C->user_list_version = version; if (TLS->callback.chat_update) { TLS->callback.chat_update (TLS, C, TGL_UPDATE_MEMBERS); } }
void bl_do_set_channel_pts (struct tgl_state *TLS, int id, int pts) /* {{{ */ { tgl_peer_t *E = tgl_peer_get (TLS, TGL_MK_CHANNEL (id)); if (!E || !(E->flags & TGLPF_CREATED)) { return; } if (E->flags & TGLCHF_DIFF) { return ; } if (E->channel.pts <= pts) { return; } E->channel.pts = pts; }
void bl_do_peer_delete (struct tgl_state *TLS, tgl_peer_id_t id) /* {{{ */ { tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P || !(P->flags & TGLPF_CREATED)) { return; } if (P->flags & TGLPF_DELETED) { return; } P->flags |= TGLPF_DELETED; switch (id.peer_type) { case TGL_PEER_USER: if (TLS->callback.user_update) { TLS->callback.user_update (TLS, (void *)P, TGL_UPDATE_DELETED); } break; case TGL_PEER_CHAT: if (TLS->callback.chat_update) { TLS->callback.chat_update (TLS, (void *)P, TGL_UPDATE_DELETED); } break; case TGL_PEER_ENCR_CHAT: if (TLS->callback.secret_chat_update) { TLS->callback.secret_chat_update (TLS, (void *)P, TGL_UPDATE_DELETED); } break; case TGL_PEER_CHANNEL: if (TLS->callback.channel_update) { TLS->callback.channel_update (TLS, (void *)P, TGL_UPDATE_DELETED); } break; default: assert (0); } }
json_t *json_pack_message (struct tgl_message *M) { json_t *res = json_object (); assert (json_object_set (res, "event", json_string ("message")) >= 0); //will overwriten to service, if service. assert (json_object_set (res, "id", json_integer (M->id)) >= 0); if (!(M->flags & TGLMF_CREATED)) { return res; } assert (json_object_set (res, "flags", json_integer (M->flags)) >= 0); if (tgl_get_peer_type (M->fwd_from_id)) { assert (json_object_set (res, "fwd_from", json_pack_peer (M->fwd_from_id, tgl_peer_get (TLS, M->fwd_from_id))) >= 0); assert (json_object_set (res, "fwd_date", json_integer (M->fwd_date)) >= 0); } if (M->reply_id) { assert (json_object_set (res, "reply_id", json_integer (M->reply_id)) >= 0); } if (M->flags & TGLMF_MENTION) { assert (json_object_set (res, "mention", json_true ()) >= 0); } assert (json_object_set (res, "from", json_pack_peer (M->from_id, tgl_peer_get (TLS, M->from_id))) >= 0); assert (json_object_set (res, "to", json_pack_peer (M->to_id, tgl_peer_get (TLS, M->to_id))) >= 0); assert (json_object_set (res, "out", json_boolean (M->flags & TGLMF_OUT)) >= 0); assert (json_object_set (res, "unread", json_boolean (M->flags & TGLMF_UNREAD)) >= 0); assert (json_object_set (res, "service", json_boolean (M->flags & TGLMF_SERVICE)) >= 0); assert (json_object_set (res, "date", json_integer (M->date)) >= 0); if (!(M->flags & TGLMF_SERVICE)) { if (M->message_len && M->message) { assert (json_object_set (res, "text", json_string (M->message)) >= 0); } if (M->media.type && M->media.type != tgl_message_media_none) { assert (json_object_set (res, "media", json_pack_media (&M->media)) >= 0); } } else { assert (json_object_set (res, "event", json_string ("service")) >= 0); assert (json_object_set (res, "action", json_pack_service (M)) >= 0); } return res; }
void tgprpl_chat_join (PurpleConnection *gc, GHashTable *data) { debug ("tgprpl_chat_join()"); g_return_if_fail(data); // auto joins will cause chat joins at a time when the dialogue list is not ready, remember // those chats and join them once the dialogue list is fetched if (! gc_get_data (gc)->dialogues_ready) { g_return_if_fail (data); const char *id = g_hash_table_lookup (data, "id"); if (id) { debug ("attempting to join chat %s while not ready, queue up for later", id); gc_get_data (gc)->pending_joins = g_list_append (gc_get_data (gc)->pending_joins, g_strdup (id)); } return; } // join existing chat by id when the user clicks on a chat in the buddy list void *value = g_hash_table_lookup (data, "id"); if (value && atoi (value)) { tgl_peer_id_t cid = TGL_MK_CHAT(atoi (value)); tgl_peer_t *P = tgl_peer_get (gc_get_tls (gc), cid); if (P) { debug ("joining chat by id %d ...", tgl_get_peer_id (cid)); tgl_do_get_chat_info (gc_get_tls (gc), cid, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL); } else { warning ("Cannot join chat %d, peer not found...", tgl_get_peer_id (cid)); purple_serv_got_join_chat_failed (gc, data); } return; } // join chat by invite link provided in the chat join window const char *link = g_hash_table_lookup (data, "link"); if (str_not_empty (link)) { tgl_do_import_chat_link (gc_get_tls (gc), link, (int)strlen (link), tgp_notify_on_error_gw, NULL); return; } // if a chat with this name doesn't exist yet, prompt to create one const char *subject = g_hash_table_lookup (data, "subject"); if (str_not_empty (subject)) { tgl_peer_t *P = tgl_peer_get_by_name (gc_get_tls (gc), subject); // handle joining chats by print_names as used by the Adium plugin if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { debug ("joining chat by subject %s ...", subject); tgl_do_get_chat_info (gc_get_tls (gc), P->id, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL); return; } // user creates a new chat by providing its subject the chat join window request_create_chat (gc_get_tls (gc), subject); } }
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); tgl_peer_t *U = tgl_peer_get (conn->TLS, TGL_MK_USER (id)); if (U) { if (typing == PURPLE_TYPING) { tgl_do_send_typing (conn->TLS, U->id, tgl_typing_typing, 0, 0); } else { tgl_do_send_typing (conn->TLS, U->id, tgl_typing_cancel, 0, 0); } } return 0; }
void read_secret_chat (int fd, int v) { int id, l, user_id, admin_id, date, ttl, layer, state; long long access_hash, key_fingerprint; static char s[1000]; static unsigned char key[256]; static unsigned char sha[20]; assert (read (fd, &id, 4) == 4); //assert (read (fd, &flags, 4) == 4); assert (read (fd, &l, 4) == 4); assert (l > 0 && l < 1000); assert (read (fd, s, l) == l); assert (read (fd, &user_id, 4) == 4); assert (read (fd, &admin_id, 4) == 4); assert (read (fd, &date, 4) == 4); assert (read (fd, &ttl, 4) == 4); assert (read (fd, &layer, 4) == 4); assert (read (fd, &access_hash, 8) == 8); assert (read (fd, &state, 4) == 4); assert (read (fd, &key_fingerprint, 8) == 8); assert (read (fd, &key, 256) == 256); if (v >= 2) { assert (read (fd, sha, 20) == 20); } int in_seq_no = 0, out_seq_no = 0, last_in_seq_no = 0; if (v >= 1) { assert (read (fd, &in_seq_no, 4) == 4); assert (read (fd, &last_in_seq_no, 4) == 4); assert (read (fd, &out_seq_no, 4) == 4); } bl_do_encr_chat_create (TLS, id, user_id, admin_id, s, l); struct tgl_secret_chat *P = (void *)tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (id)); assert (P && (P->flags & FLAG_CREATED)); bl_do_encr_chat_set_date (TLS, P, date); bl_do_encr_chat_set_ttl (TLS, P, ttl); bl_do_encr_chat_set_layer (TLS ,P, layer); bl_do_encr_chat_set_access_hash (TLS, P, access_hash); bl_do_encr_chat_set_state (TLS, P, state); bl_do_encr_chat_set_key (TLS, P, key, key_fingerprint); if (v >= 2) { bl_do_encr_chat_set_sha (TLS, P, sha); } else { SHA1 ((void *)key, 256, sha); bl_do_encr_chat_set_sha (TLS, P, sha); } if (v >= 1) { bl_do_encr_chat_set_seq (TLS, P, in_seq_no, last_in_seq_no, out_seq_no); } }
void bl_do_encr_chat_exchange (struct tgl_state *TLS, tgl_peer_id_t id, long long *exchange_id, const void *key, int *state) /* {{{ */ { tgl_peer_t *P = tgl_peer_get (TLS, id); if (!P) { return; } if (state) { P->encr_chat.exchange_state = *state; } if (exchange_id) { P->encr_chat.exchange_id = *exchange_id; } static unsigned char sha_buffer[20]; switch (P->encr_chat.exchange_state) { case tgl_sce_requested: memcpy (P->encr_chat.exchange_key, key, 256); break; case tgl_sce_accepted: memcpy (P->encr_chat.exchange_key, key, 256); TGLC_sha1 ((unsigned char *)P->encr_chat.exchange_key, 256, sha_buffer); P->encr_chat.exchange_key_fingerprint = *(long long *)(sha_buffer + 12); break; case tgl_sce_committed: memcpy (P->encr_chat.exchange_key, P->encr_chat.key, 256); P->encr_chat.exchange_key_fingerprint = P->encr_chat.key_fingerprint; memcpy (P->encr_chat.key, key, 256); TGLC_sha1 ((unsigned char *)P->encr_chat.key, 256, sha_buffer); P->encr_chat.key_fingerprint = *(long long *)(sha_buffer + 12); break; case tgl_sce_confirmed: P->encr_chat.exchange_state = tgl_sce_none; if (P->encr_chat.exchange_state != tgl_sce_committed) { memcpy (P->encr_chat.key, P->encr_chat.exchange_key, 256); P->encr_chat.key_fingerprint = P->encr_chat.exchange_key_fingerprint; } break; case tgl_sce_aborted: P->encr_chat.exchange_state = tgl_sce_none; if (P->encr_chat.exchange_state == tgl_sce_committed) { memcpy (P->encr_chat.key, P->encr_chat.exchange_key, 256); P->encr_chat.key_fingerprint = P->encr_chat.exchange_key_fingerprint; } break; default: assert (0); } }
tgl_peer_t *tgp_blist_peer_find (struct tgl_state *TLS, const char *purple_name) { // buddies will keep the name they had when they were first added to the user list. The print_name // of the peer may have changed since then, therefore the ID stored in the buddy is used to fetch // the user name. PurpleBuddy *buddy = purple_find_buddy (tg_get_acc (TLS), purple_name); if (! buddy) { // foreign users are not in the buddy list by default, therefore the name used by libpurple and the // print name is always identical return tgl_peer_get_by_name (TLS, purple_name); } if (! tgp_blist_buddy_has_id (buddy)) { return NULL; } return tgl_peer_get (TLS, tgp_blist_buddy_get_id (buddy)); }
void tgl_do_send_encr_msg (struct tgl_state *TLS, struct tgl_message *M, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { if (M->flags & TGLMF_SERVICE) { tgl_do_send_encr_msg_action (TLS, M, callback, callback_extra); return; } tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); if (!P || P->encr_chat.state != sc_ok) { vlogprintf (E_WARNING, "Unknown encrypted chat\n"); if (callback) { callback (TLS, callback_extra, 0, M); } return; } assert (M->flags & TGLMF_ENCRYPTED); clear_packet (); out_int (CODE_messages_send_encrypted); out_int (CODE_input_encrypted_chat); out_int (tgl_get_peer_id (M->to_id)); out_long (P->encr_chat.access_hash); out_long (M->id); encr_start (); out_int (CODE_decrypted_message_layer); out_random (15 + 4 * (lrand48 () % 3)); out_int (TGL_ENCRYPTED_LAYER); out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != TLS->our_id)); out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == TLS->our_id) - 2); out_int (CODE_decrypted_message); out_long (M->id); out_int (P->encr_chat.ttl); out_cstring ((void *)M->message, M->message_len); switch (M->media.type) { case tgl_message_media_none: out_int (CODE_decrypted_message_media_empty); break; case tgl_message_media_geo: out_int (CODE_decrypted_message_media_geo_point); out_double (M->media.geo.latitude); out_double (M->media.geo.longitude); break; default: assert (0); } encr_finish (&P->encr_chat); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M, callback, callback_extra); }
static int msg_send_encr_on_error (struct tgl_state *TLS, struct query *q, int error_code, int error_len, const char *error) { struct tgl_message *M = q->extra; tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); if (P && P->encr_chat.state != sc_deleted && error_code == 400) { if (strncmp (error, "ENCRYPTION_DECLINED", 19) == 0) { bl_do_encr_chat_delete (TLS, &P->encr_chat); } } if (q->callback) { ((void (*)(struct tgl_state *TLS, void *, int, struct tgl_message *))q->callback) (TLS, q->callback_extra, 0, M); } if (M) { bl_do_message_delete (TLS, M); } return 0; }
static void tgprpl_tooltip_text (PurpleBuddy * buddy, PurpleNotifyUserInfo * info, gboolean full) { debug ("tgprpl_tooltip_text()\n", buddy->name); tgl_peer_id_t *peer = purple_buddy_get_protocol_data(buddy); if (!peer) { purple_notify_user_info_add_pair_plaintext(info, "Status", "Offline"); return; } tgl_peer_t *P = tgl_peer_get (get_conn_from_buddy (buddy)->TLS, *peer); if (!P) { warning ("tgprpl_tooltip_text: warning peer with id %d not found in tree.\n", peer->id); return; } purple_notify_user_info_add_pair_plaintext (info, "Status", format_status(&P->user.status)); purple_notify_user_info_add_pair_plaintext (info, "Last seen: ", format_time(P->user.status.when)); }
PurpleConversation *chat_show (PurpleConnection *gc, int id) { connection_data *conn = purple_connection_get_protocol_data(gc); PurpleConversation *convo = purple_find_chat (gc, id); PurpleConvChat *chat = purple_conversation_get_chat_data (convo); tgl_peer_t *P = tgl_peer_get (conn->TLS, TGL_MK_CHAT(id)); if (! P) { warning ("Chat %d not existing, not showing...", id); return NULL; } if (! convo || (chat && purple_conv_chat_has_left (chat))) { convo = p2tgl_got_joined_chat (conn->TLS, &P->chat); } chat_users_update (conn->TLS, &P->chat); return convo; }
void json_pack_chat (json_t *res, tgl_peer_t *P) { assert (P->chat.title); assert (json_object_set (res, "title", json_string (P->chat.title)) >= 0); assert (json_object_set (res, "members_num", json_integer (P->chat.users_num)) >= 0); if (P->chat.user_list) { json_t *m = json_array (); assert (m); int i; for (i = 0; i < P->chat.users_num; i++) { tgl_peer_id_t id = TGL_MK_USER (P->chat.user_list[i].user_id); assert (json_array_append (m, json_pack_peer (id, tgl_peer_get (TLS, id))) >= 0); } assert (json_object_set (res, "members", m) >= 0); } }
void tgprpl_chat_join (PurpleConnection * gc, GHashTable *data) { debug ("tgprpl_chat_join()"); connection_data *conn = purple_connection_get_protocol_data (gc); // join existing chat by id when the user clicks on a chat in the buddy list void *value = g_hash_table_lookup (data, "id"); if (value && atoi (value)) { tgl_peer_id_t cid = TGL_MK_CHAT(atoi (value)); tgl_peer_t *P = tgl_peer_get (conn->TLS, cid); if (P) { debug ("joining chat by id %d ...", tgl_get_peer_id (cid)); tgl_do_get_chat_info (conn->TLS, cid, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL); } else { warning ("Cannot join chat %d, peer not found...", tgl_get_peer_id (cid)); purple_serv_got_join_chat_failed (gc, data); } return; } // join chat by invite link provided in the chat join window const char *link = g_hash_table_lookup (data, "link"); if (str_not_empty (link)) { tgl_do_import_chat_link (conn->TLS, link, (int)strlen (link), tgp_notify_on_error_gw, NULL); return; } // if a chat with this name doesn't exist yet, prompt to create one const char *subject = g_hash_table_lookup (data, "subject"); if (str_not_empty (subject)) { tgl_peer_t *P = tgl_peer_get_by_name (conn->TLS, subject); // handle joining chats by print_names as used by the Adium plugin if (P && tgl_get_peer_type (P->id) == TGL_PEER_CHAT) { debug ("joining chat by subject %s ...", subject); tgl_do_get_chat_info (conn->TLS, P->id, FALSE, tgp_chat_on_loaded_chat_full_joining, NULL); return; } // user creates a new chat by providing its subject the chat join window request_create_chat (conn->TLS, subject); } }
static void tgp_chat_add_all_users (struct tgl_state *TLS, PurpleConversation *conv, struct tgl_chat *C) { GList *users = NULL, *flags = NULL; int i = 0; for (; i < C->user_list_size; i++) { struct tgl_chat_user *uid = (C->user_list + i); users = g_list_append (users, g_strdup_printf ("%d", uid->user_id)); flags = g_list_append (flags, GINT_TO_POINTER(C->admin_id == uid->user_id ? PURPLE_CBFLAGS_FOUNDER : PURPLE_CBFLAGS_NONE)); } purple_conv_chat_add_users (PURPLE_CONV_CHAT(conv), users, NULL, flags, FALSE); while (users) { p2tgl_conv_add_user_rename (tgl_peer_get (TLS, TGL_MK_USER(atoi (users->data))), conv); users = g_list_next (users); } g_list_free_full (users, g_free); g_list_free (flags); }
void py_dialog_list_cb (struct tgl_state *TLSR, void *cb_extra, int success, int num, tgl_peer_id_t peers[], int msgs[], int unread[]) { assert (TLSR == TLS); PyObject *callable = cb_extra; PyObject *arglist = NULL; PyObject *dialog_list = NULL; PyObject *dialog = NULL; PyObject *result = NULL; if(PyCallable_Check(callable)) { dialog_list = PyList_New(0); if (success) { int i; for (i = 0; i < num; i++) { dialog = PyDict_New(); PyDict_SetItemString(dialog, "peer", get_peer(peers[i], tgl_peer_get (TLS, peers[i]))); struct tgl_message *M = tgl_message_get (TLS, msgs[i]); if (M && (M->flags & TGLMF_CREATED)) { PyDict_SetItemString(dialog, "message", get_message(M)); } PyDict_SetItemString(dialog, "unread", unread[i] ? Py_True : Py_False); PyList_Append(dialog_list, dialog); } } arglist = Py_BuildValue("(OO)", success ? Py_True : Py_False, dialog_list); result = PyEval_CallObject(callable, arglist); Py_DECREF(arglist); if(result == NULL) PyErr_Print(); Py_XDECREF(result); } Py_XDECREF(callable); }
static char *format_service_msg (struct tgl_state *TLS, struct tgl_message *M) { assert (M && M->service); char *txt_user = NULL; char *txt_action = NULL; char *txt = NULL; tgl_peer_t *peer = tgl_peer_get (TLS, M->from_id); if (! peer) { return NULL; } txt_user = p2tgl_strdup_alias (peer); switch (M->action.type) { case tgl_message_action_chat_create: txt_action = g_strdup_printf ("created chat %s", M->action.title); break; case tgl_message_action_chat_edit_title: txt_action = g_strdup_printf ("changed title to %s", M->action.new_title); break; case tgl_message_action_chat_edit_photo: txt_action = g_strdup ("changed photo"); break; case tgl_message_action_chat_delete_photo: txt_action = g_strdup ("deleted photo"); break; case tgl_message_action_chat_add_user: { tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user)); if (peer) { char *alias = p2tgl_strdup_alias (peer); txt_action = g_strdup_printf ("added user %s", alias); g_free (alias); } break; } case tgl_message_action_chat_delete_user: { tgl_peer_t *peer = tgl_peer_get (TLS, TGL_MK_USER (M->action.user)); if (peer) { char *alias = p2tgl_strdup_alias (peer); txt_action = g_strdup_printf ("deleted user %s", alias); g_free (alias); } break; } case tgl_message_action_set_message_ttl: txt_action = g_strdup_printf ("set ttl to %d seconds", M->action.ttl); break; case tgl_message_action_read_messages: txt_action = g_strdup_printf ("%d messages marked read", M->action.read_cnt); break; case tgl_message_action_delete_messages: txt_action = g_strdup_printf ("%d messages deleted", M->action.delete_cnt); break; case tgl_message_action_screenshot_messages: txt_action = g_strdup_printf ("%d messages screenshoted", M->action.screenshot_cnt); break; case tgl_message_action_notify_layer: txt_action = g_strdup_printf ("updated layer to %d", M->action.layer); break; /* case tgl_message_action_request_key: txt_action = g_strdup_printf ("Request rekey #%016llx\n", M->action.exchange_id); break; case tgl_message_action_accept_key: txt_action = g_strdup_printf ("Accept rekey #%016llx\n", M->action.exchange_id); break; case tgl_message_action_commit_key: txt_action = g_strdup_printf ("Commit rekey #%016llx\n", M->action.exchange_id); break; case tgl_message_action_abort_key: txt_action = g_strdup_printf ("Abort rekey #%016llx\n", M->action.exchange_id); break; */ default: txt_action = NULL; break; } if (txt_action) { debug ("SERVICE MESSAGE: %s", txt_action); txt = g_strdup_printf ("%s %s.", txt_user, txt_action); g_free (txt_action); } g_free (txt_user); return txt; }
tgl_peer_t *tgp_blist_buddy_get_peer (PurpleBuddy *buddy) { if (! tgp_blist_buddy_has_id (buddy)) { return NULL; } return tgl_peer_get (pbn_get_conn (&buddy->node)->TLS, tgp_blist_buddy_get_id (buddy)); }
void json_pack_encr_chat (json_t *res, tgl_peer_t *P) { assert (json_object_set (res, "user", json_pack_peer (TGL_MK_USER (P->encr_chat.user_id), tgl_peer_get (TLS, TGL_MK_USER (P->encr_chat.user_id)))) >= 0); }
void tgl_do_send_create_encr_chat (struct tgl_state *TLS, void *x, unsigned char *random, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_secret_chat *E), void *callback_extra) { int user_id = (long)x; int i; unsigned char random_here[256]; tglt_secure_random (random_here, 256); for (i = 0; i < 256; i++) { random[i] ^= random_here[i]; } BIGNUM *a = BN_bin2bn (random, 256, 0); ensure_ptr (a); BIGNUM *p = BN_bin2bn (TLS->encr_prime, 256, 0); ensure_ptr (p); BIGNUM *g = BN_new (); ensure_ptr (g); ensure (BN_set_word (g, TLS->encr_root)); BIGNUM *r = BN_new (); ensure_ptr (r); ensure (BN_mod_exp (r, g, a, p, TLS->BN_ctx)); BN_clear_free (a); static char g_a[256]; memset (g_a, 0, 256); BN_bn2bin (r, (void *)(g_a + (256 - BN_num_bytes (r)))); int t = lrand48 (); while (tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (t))) { t = lrand48 (); } //bl_do_encr_chat_init (TLS, t, user_id, (void *)random, (void *)g_a); int state = sc_waiting; bl_do_encr_chat_new (TLS, t, NULL, NULL, &TLS->our_id, &user_id, random, NULL, NULL, &state, NULL, NULL, NULL, NULL, NULL, NULL, TGLPF_CREATE | TGLPF_CREATED); tgl_peer_t *_E = tgl_peer_get (TLS, TGL_MK_ENCR_CHAT (t)); assert (_E); struct tgl_secret_chat *E = &_E->encr_chat; clear_packet (); out_int (CODE_messages_request_encryption); tgl_peer_t *U = tgl_peer_get (TLS, TGL_MK_USER (E->user_id)); assert (U); if (U && U->user.access_hash) { out_int (CODE_input_user_foreign); out_int (E->user_id); out_long (U->user.access_hash); } else { out_int (CODE_input_user_contact); out_int (E->user_id); } out_int (tgl_get_peer_id (E->id)); out_cstring (g_a, 256); //write_secret_chat_file (); BN_clear_free (g); BN_clear_free (p); BN_clear_free (r); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_request_methods, E, callback, callback_extra); }
static void send_file_encrypted_end (struct tgl_state *TLS, struct send_file *f, void *callback, void *callback_extra) { out_int (CODE_messages_send_encrypted_file); out_int (CODE_input_encrypted_chat); out_int (tgl_get_peer_id (f->to_id)); tgl_peer_t *P = tgl_peer_get (TLS, f->to_id); assert (P); out_long (P->encr_chat.access_hash); long long r; tglt_secure_random (&r, 8); out_long (r); encr_start (); out_int (CODE_decrypted_message_layer); out_random (15 + 4 * (lrand48 () % 3)); out_int (TGL_ENCRYPTED_LAYER); out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != TLS->our_id)); out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == TLS->our_id)); out_int (CODE_decrypted_message); out_long (r); out_int (P->encr_chat.ttl); out_string (""); int *save_ptr = packet_ptr; if (f->flags == -1) { out_int (CODE_decrypted_message_media_photo); } else if ((f->flags & TGLDF_VIDEO)) { out_int (CODE_decrypted_message_media_video); } else if ((f->flags & TGLDF_AUDIO)) { out_int (CODE_decrypted_message_media_audio); } else { out_int (CODE_decrypted_message_media_document); } if (f->flags == -1 || !(f->flags & TGLDF_AUDIO)) { out_cstring ("", 0); out_int (90); out_int (90); } if (f->flags == -1) { out_int (f->w); out_int (f->h); } else if (f->flags & TGLDF_VIDEO) { out_int (f->duration); out_string (tg_mime_by_filename (f->file_name)); out_int (f->w); out_int (f->h); } else if (f->flags & TGLDF_AUDIO) { out_int (f->duration); out_string (tg_mime_by_filename (f->file_name)); } else { out_string (""); out_string (tg_mime_by_filename (f->file_name)); // document } out_int (f->size); out_cstring ((void *)f->key, 32); out_cstring ((void *)f->init_iv, 32); int *save_in_ptr = in_ptr; int *save_in_end = in_end; in_ptr = save_ptr; in_end = packet_ptr; assert (skip_type_any (TYPE_TO_PARAM(decrypted_message_media)) >= 0); assert (in_ptr == in_end); in_ptr = save_ptr; in_end = packet_ptr; struct tl_ds_decrypted_message_media *DS_DMM = fetch_ds_type_decrypted_message_media (TYPE_TO_PARAM (decrypted_message_media)); in_end = save_in_ptr; in_ptr = save_in_end; int peer_type = tgl_get_peer_type (f->to_id); int peer_id = tgl_get_peer_id (f->to_id); int date = time (NULL); encr_finish (&P->encr_chat); if (f->size < (16 << 20)) { out_int (CODE_input_encrypted_file_uploaded); } else { out_int (CODE_input_encrypted_file_big_uploaded); } out_long (f->id); out_int (f->part_num); if (f->size < (16 << 20)) { out_string (""); } unsigned char md5[16]; unsigned char str[64]; memcpy (str, f->key, 32); memcpy (str + 32, f->init_iv, 32); MD5 (str, 64, md5); out_int ((*(int *)md5) ^ (*(int *)(md5 + 4))); tfree_secure (f->iv, 32); bl_do_create_message_encr_new (TLS, r, &TLS->our_id, &peer_type, &peer_id, &date, NULL, 0, DS_DMM, NULL, NULL, TGLMF_OUT | TGLMF_UNREAD | TGLMF_ENCRYPTED | TGLMF_CREATE | TGLMF_CREATED); free_ds_type_decrypted_message_media (DS_DMM, TYPE_TO_PARAM (decrypted_message_media)); struct tgl_message *M = tgl_message_get (TLS, r); assert (M); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &send_encr_file_methods, M, callback, callback_extra); tfree_str (f->file_name); tfree (f, sizeof (*f)); }
void tgl_do_messages_mark_read_encr (struct tgl_state *TLS, tgl_peer_id_t id, long long access_hash, int last_time, void (*callback)(struct tgl_state *TLS, void *callback_extra, int), void *callback_extra) { clear_packet (); out_int (CODE_messages_read_encrypted_history); out_int (CODE_input_encrypted_chat); out_int (tgl_get_peer_id (id)); out_long (access_hash); out_int (last_time); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &mark_read_encr_methods, tgl_peer_get (TLS, id), callback, callback_extra); }
int loop (void) { tgl_set_callback (TLS, &upd_cb); struct event_base *ev = event_base_new (); tgl_set_ev_base (TLS, ev); tgl_set_net_methods (TLS, &tgl_conn_methods); tgl_set_timer_methods (TLS, &tgl_libevent_timers); assert (TLS->timer_methods); tgl_set_download_directory (TLS, get_downloads_directory ()); tgl_register_app_id (TLS, TELEGRAM_CLI_APP_ID, TELEGRAM_CLI_APP_HASH); tgl_set_app_version (TLS, "Telegram-cli " TELEGRAM_CLI_VERSION); if (ipv6_enabled) { tgl_enable_ipv6 (TLS); } if (bot_mode) { tgl_enable_bot (TLS); } if (disable_link_preview) { tgl_disable_link_preview (TLS); } assert (tgl_init (TLS) >= 0); /*if (binlog_enabled) { double t = tglt_get_double_time (); if (verbosity >= E_DEBUG) { logprintf ("replay log start\n"); } tgl_replay_log (TLS); if (verbosity >= E_DEBUG) { logprintf ("replay log end in %lf seconds\n", tglt_get_double_time () - t); } tgl_reopen_binlog_for_writing (TLS); } else {*/ read_auth_file (); read_state_file (); read_secret_chat_file (); //} binlog_read = 1; #ifdef USE_LUA lua_binlog_end (); #endif #ifdef USE_PYTHON py_binlog_end (); #endif if (sfd >= 0) { struct event *ev = event_new (TLS->ev_base, sfd, EV_READ | EV_PERSIST, accept_incoming, 0); event_add (ev, 0); } if (usfd >= 0) { struct event *ev = event_new (TLS->ev_base, usfd, EV_READ | EV_PERSIST, accept_incoming, 0); event_add (ev, 0); } update_prompt (); if (reset_authorization) { tgl_peer_t *P = tgl_peer_get (TLS, TLS->our_id); if (P && P->user.phone && reset_authorization == 1) { set_default_username (P->user.phone); } bl_do_reset_authorization (TLS); } set_interface_callbacks (); tgl_login (TLS); net_loop (); return 0; }
void tgl_do_send_encr_msg_action (struct tgl_state *TLS, struct tgl_message *M, void (*callback)(struct tgl_state *TLS, void *callback_extra, int success, struct tgl_message *M), void *callback_extra) { tgl_peer_t *P = tgl_peer_get (TLS, M->to_id); if (!P || P->encr_chat.state != sc_ok) { vlogprintf (E_WARNING, "Unknown encrypted chat\n"); if (callback) { callback (TLS, callback_extra, 0, 0); } return; } assert (M->flags & TGLMF_ENCRYPTED); clear_packet (); out_int (CODE_messages_send_encrypted_service); out_int (CODE_input_encrypted_chat); out_int (tgl_get_peer_id (M->to_id)); out_long (P->encr_chat.access_hash); out_long (M->id); encr_start (); out_int (CODE_decrypted_message_layer); out_random (15 + 4 * (lrand48 () % 3)); out_int (TGL_ENCRYPTED_LAYER); out_int (2 * P->encr_chat.in_seq_no + (P->encr_chat.admin_id != TLS->our_id)); out_int (2 * P->encr_chat.out_seq_no + (P->encr_chat.admin_id == TLS->our_id) - 2); out_int (CODE_decrypted_message_service); out_long (M->id); switch (M->action.type) { case tgl_message_action_notify_layer: out_int (CODE_decrypted_message_action_notify_layer); out_int (M->action.layer); break; case tgl_message_action_set_message_ttl: out_int (CODE_decrypted_message_action_set_message_t_t_l); out_int (M->action.ttl); break; case tgl_message_action_request_key: out_int (CODE_decrypted_message_action_request_key); out_long (M->action.exchange_id); out_cstring ((void *)M->action.g_a, 256); break; case tgl_message_action_accept_key: out_int (CODE_decrypted_message_action_accept_key); out_long (M->action.exchange_id); out_cstring ((void *)M->action.g_a, 256); out_long (M->action.key_fingerprint); break; case tgl_message_action_commit_key: out_int (CODE_decrypted_message_action_commit_key); out_long (M->action.exchange_id); out_long (M->action.key_fingerprint); break; case tgl_message_action_abort_key: out_int (CODE_decrypted_message_action_abort_key); out_long (M->action.exchange_id); break; case tgl_message_action_noop: out_int (CODE_decrypted_message_action_noop); break; default: assert (0); } encr_finish (&P->encr_chat); tglq_send_query (TLS, TLS->DC_working, packet_ptr - packet_buffer, packet_buffer, &msg_send_encr_methods, M, callback, callback_extra); }
static void tgp_msg_display (struct tgl_state *TLS, struct tgp_msg_loading *C) { connection_data *conn = TLS->ev_base; struct tgl_message *M = C->msg; char *text = NULL; int flags = 0; // only display new messages, ignore updates or deletions if ((M->flags & (TGLMF_EMPTY | TGLMF_DELETED)) || !(M->flags & TGLMF_CREATED) || !M->message || tgp_outgoing_msg (TLS, M) || !tgl_get_peer_type (M->to_id)) { return; } if (M->flags & TGLMF_SERVICE) { text = format_service_msg (TLS, M); flags |= PURPLE_MESSAGE_SYSTEM; } else if (M->media.type == tgl_message_media_document && M->media.document->flags & TGLDF_STICKER) { #ifdef HAVE_LIBWEBP char *filename = C->data; int img = p2tgl_imgstore_add_with_id_webp (filename); if (img <= 0) { failure ("Cannot display sticker, adding to imgstore failed"); return; } used_images_add (conn, img); text = format_img_full (img); flags |= PURPLE_MESSAGE_IMAGES; g_free (filename); #else char *txt_user = p2tgl_strdup_alias (tgl_peer_get (TLS, M->from_id)); text = g_strdup_printf ("%s sent a sticker", txt_user); flags |= PURPLE_MESSAGE_SYSTEM; g_free (txt_user); #endif } else if (M->media.type == tgl_message_media_photo || (M->media.type == tgl_message_media_document_encr && M->media.encr_document->flags & TGLDF_IMAGE)) { char *filename = C->data; int img = p2tgl_imgstore_add_with_id (filename); if (img <= 0) { failure ("Cannot display picture message, adding to imgstore failed."); return; } used_images_add (conn, img); text = format_img_full (img); flags |= PURPLE_MESSAGE_IMAGES; g_free (filename); } else if (M->media.type == tgl_message_media_document) { char *who = p2tgl_strdup_id (M->from_id); if (! tgp_our_msg(TLS, M)) { tgprpl_recv_file (conn->gc, who, M->media.document); } g_free (who); return; } else if (M->media.type == tgl_message_media_document_encr) { char *who = p2tgl_strdup_id (M->to_id); if (! tgp_our_msg(TLS, M)) { tgprpl_recv_encr_file (conn->gc, who, M->media.encr_document); } g_free (who); return; } else { text = format_message (M); flags |= PURPLE_MESSAGE_RECV; } if (! text || ! *text) { warning ("No text to display"); return; } switch (tgl_get_peer_type (M->to_id)) { case TGL_PEER_CHAT: { if (chat_show (conn->gc, tgl_get_peer_id (M->to_id))) { p2tgl_got_chat_in (TLS, M->to_id, M->from_id, text, flags, M->date); } pending_reads_add (conn->pending_reads, M->to_id); break; } case TGL_PEER_ENCR_CHAT: { p2tgl_got_im (TLS, M->to_id, text, flags, M->date); pending_reads_add (conn->pending_reads, M->to_id); break; } case TGL_PEER_USER: { if (tgp_our_msg (TLS, M)) { flags |= PURPLE_MESSAGE_SEND; flags &= ~PURPLE_MESSAGE_RECV; p2tgl_got_im_combo (TLS, M->to_id, text, flags, M->date); } else { p2tgl_got_im (TLS, M->from_id, text, flags, M->date); pending_reads_add (conn->pending_reads, M->from_id); } break; } } if (p2tgl_status_is_present (purple_account_get_active_status (conn->pa)) && p2tgl_send_notifications(conn->pa)) { pending_reads_send_all (conn->pending_reads, conn->TLS); } g_free (text); }