diff --git a/constants.h b/constants.h index 7998efc..fbd674f 100644 --- a/constants.h +++ b/constants.h @@ -258,6 +258,25 @@ #define CODE_input_encrypted_file_big_uploaded 0x2dc173c8 #define CODE_update_chat_participant_add 0x3a0eeb22 #define CODE_update_chat_participant_delete 0x6e5f8c22 +#define CODE_input_media_uploaded_audio 0x61a6d436 +#define CODE_input_media_audio 0x89938781 +#define CODE_input_media_uploaded_document 0x34e794bd +#define CODE_input_media_uploaded_thumb_document 0x3e46de5d +#define CODE_input_media_document 0xd184e841 +#define CODE_message_media_document 0x2fda2204 +#define CODE_message_media_audio 0xc6b68300 +#define CODE_input_audio_empty 0xd95adc84 +#define CODE_input_audio 0x77d440ff +#define CODE_input_document_empty 0x72f0eaae +#define CODE_input_document 0x18798952 +#define CODE_input_audio_file_location 0x74dc404d +#define CODE_input_document_file_location 0x4e45abe9 +#define CODE_decrypted_message_media_document 0xb095434b +#define CODE_decrypted_message_media_audio 0x6080758f +#define CODE_audio_empty 0x586988d8 +#define CODE_audio 0x427425e7 +#define CODE_document_empty 0x36f8c871 +#define CODE_document 0x9efc6326 #define CODE_invoke_after_msg 0xcb9f372d #define CODE_invoke_after_msgs 0x3dc4b4f0 #define CODE_invoke_with_layer1 0x53835315 diff --git a/gen_constants_h.awk b/gen_constants_h.awk index 5088914..06e6835 100644 --- a/gen_constants_h.awk +++ b/gen_constants_h.awk @@ -1,4 +1,22 @@ BEGIN { + print "/*"; + print " This file is part of telegram-client."; + print ""; + print " Telegram-client is free software: you can redistribute it and/or modify"; + print " it under the terms of the GNU General Public License as published by"; + print " the Free Software Foundation, either version 2 of the License, or"; + print " (at your option) any later version."; + print ""; + print " Telegram-client is distributed in the hope that it will be useful,"; + print " but WITHOUT ANY WARRANTY; without even the implied warranty of"; + print " MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the"; + print " GNU General Public License for more details."; + print ""; + print " You should have received a copy of the GNU General Public License"; + print " along with this telegram-client. If not, see ."; + print ""; + print " Copyright Vitaly Valtman 2013"; + print "*/"; print "#ifndef CONSTANTS_H"; print "#define CONSTANTS_H"; } diff --git a/interface.c b/interface.c index 3d87912..65889d3 100644 --- a/interface.c +++ b/interface.c @@ -278,6 +278,14 @@ char *commands[] = { "status_offline", "contacts_search", "quit", + "send_audio", + "load_audio", + "view_audio", + "send_document", + "load_document_thumb", + "view_document_thumb", + "load_document", + "view_document", 0 }; int commands_flags[] = { @@ -315,6 +323,10 @@ int commands_flags[] = { 07, 07, 07, + 0732, + 07, + 07, + 0732, }; int get_complete_mode (void) { @@ -822,6 +834,110 @@ void interpreter (char *line UU) { RET; } do_contacts_search (100, s); + } else if (IS_WORD("send_audio")) { + GET_PEER; + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty file name\n"); + RET; + } + do_send_photo (CODE_input_media_uploaded_audio, id, strndup (s, t)); + } else if (IS_WORD("send_document")) { + GET_PEER; + int t; + char *s = next_token (&t); + if (!s) { + printf ("Empty file name\n"); + RET; + } + do_send_photo (CODE_input_media_uploaded_document, id, strndup (s, t)); + } else if (IS_WORD ("load_audio")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_audio) { + do_load_video (&M->media.video, 1); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) { + do_load_encr_video (&M->media.encr_video, 1); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("view_audio")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_audio) { + do_load_video (&M->media.video, 2); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_audio) { + do_load_encr_video (&M->media.encr_video, 2); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("load_document_thumb")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + do_load_video_thumb (&M->media.video, 1); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("view_document_thumb")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + do_load_video_thumb (&M->media.video, 2); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("load_document")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + do_load_video (&M->media.video, 1); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) { + do_load_encr_video (&M->media.encr_video, 1); + } else { + printf ("Bad msg id\n"); + RET; + } + } else if (IS_WORD ("view_document")) { + long long num = next_token_int (); + if (num == NOT_FOUND) { + printf ("Bad msg id\n"); + RET; + } + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_document) { + do_load_video (&M->media.video, 2); + } else if (M && !M->service && M->media.type == (int)CODE_decrypted_message_media_document) { + do_load_encr_video (&M->media.encr_video, 2); + } else { + printf ("Bad msg id\n"); + RET; + } } else if (IS_WORD ("quit")) { exit (0); } @@ -933,12 +1049,28 @@ void print_media (struct message_media *M) { case CODE_message_media_video: printf ("[video]"); return; + case CODE_message_media_audio: + printf ("[audio]"); + return; + case CODE_message_media_document: + if (M->document.mime_type && M->document.caption) { + printf ("[document %s: type %s]", M->document.caption, M->document.mime_type); + } else { + printf ("[document]"); + } + return; case CODE_decrypted_message_media_photo: printf ("[photo]"); return; case CODE_decrypted_message_media_video: printf ("[video]"); return; + case CODE_decrypted_message_media_audio: + printf ("[audio]"); + return; + case CODE_decrypted_message_media_document: + printf ("[document]"); + return; case CODE_message_media_geo: printf ("[geo] https://maps.google.com/?q=%.6lf,%.6lf", M->geo.latitude, M->geo.longitude); return; @@ -1055,7 +1187,11 @@ void print_service_message (struct message *M) { print_date (M->date); pop_color (); printf (" "); - print_chat_name (M->to_id, user_chat_get (M->to_id)); + if (get_peer_type (M->to_id) == PEER_CHAT) { + print_chat_name (M->to_id, user_chat_get (M->to_id)); + } else { + print_encr_chat_name (M->to_id, user_chat_get (M->to_id)); + } printf (" "); print_user_name (M->from_id, user_chat_get (M->from_id)); @@ -1086,6 +1222,9 @@ void print_service_message (struct message *M) { print_user_name (set_peer_id (PEER_USER, M->action.user), user_chat_get (set_peer_id (PEER_USER, M->action.user))); printf ("\n"); break; + case CODE_decrypted_message_action_set_message_t_t_l: + printf (" set ttl to %d seconds. Unsupported yet\n", M->action.ttl); + break; default: assert (0); } diff --git a/net.c b/net.c index 4db2677..546f48d 100644 --- a/net.c +++ b/net.c @@ -240,6 +240,7 @@ struct connection *create_connection (const char *host, int port, struct session struct pollfd s; s.fd = fd; s.events = POLLOUT | POLLERR | POLLRDHUP | POLLHUP; + errno = 0; while (poll (&s, 1, 10000) <= 0 || !(s.revents & POLLOUT)) { if (errno == EINTR) { continue; } @@ -247,7 +248,7 @@ struct connection *create_connection (const char *host, int port, struct session logprintf ("Problems in poll: %m\n"); exit (1); } - logprintf ("Connect timeout\n"); + logprintf ("Connect with %s:%d timeout\n", host, port); close (fd); free (c); return 0; diff --git a/queries.c b/queries.c index 7b58fb2..a470e49 100644 --- a/queries.c +++ b/queries.c @@ -1284,7 +1284,7 @@ void send_part (struct send_file *f) { cur_uploading_bytes -= f->size; update_prompt (); clear_packet (); - assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video); + assert (f->media_type == CODE_input_media_uploaded_photo || f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_audio || f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document); if (!f->encr) { out_int (CODE_messages_send_media); out_peer_id (f->to_id); @@ -1302,7 +1302,7 @@ void send_part (struct send_file *f) { if (f->size < (16 << 20)) { out_string (""); } - if (f->media_type == CODE_input_media_uploaded_thumb_video) { + if (f->media_type == CODE_input_media_uploaded_thumb_video || f->media_type == CODE_input_media_uploaded_thumb_document) { out_int (CODE_input_file); out_long (f->thumb_id); out_int (1); @@ -1314,6 +1314,14 @@ void send_part (struct send_file *f) { out_int (100); out_int (100); } + if (f->media_type == CODE_input_media_uploaded_document || f->media_type == CODE_input_media_uploaded_thumb_document) { + out_string (s + 1); + out_string ("text"); + } + if (f->media_type == CODE_input_media_uploaded_audio) { + out_int (60); + } + out_long (-lrand48 () * (1ll << 32) - lrand48 ()); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); } else { @@ -1336,18 +1344,37 @@ void send_part (struct send_file *f) { if (f->media_type == CODE_input_media_uploaded_photo) { out_int (CODE_decrypted_message_media_photo); M->media.type = CODE_decrypted_message_media_photo; - } else { + } else if (f->media_type == CODE_input_media_uploaded_video) { out_int (CODE_decrypted_message_media_video); M->media.type = CODE_decrypted_message_media_video; + } else if (f->media_type == CODE_input_media_uploaded_audio) { + out_int (CODE_decrypted_message_media_audio); + M->media.type = CODE_decrypted_message_media_audio; + } else if (f->media_type == CODE_input_media_uploaded_document) { + out_int (CODE_decrypted_message_media_document); + M->media.type = CODE_decrypted_message_media_document;; + } else { + assert (0); + } + if (f->media_type != CODE_input_media_uploaded_audio) { + out_cstring ((void *)thumb_file, thumb_file_size); + out_int (90); + out_int (90); } - out_cstring ((void *)thumb_file, thumb_file_size); - out_int (90); - out_int (90); if (f->media_type == CODE_input_media_uploaded_video) { out_int (0); } - out_int (100); - out_int (100); + if (f->media_type == CODE_input_media_uploaded_document) { + out_string (f->file_name); + out_string ("text"); + } + if (f->media_type == CODE_input_media_uploaded_audio) { + out_int (60); + } + if (f->media_type == CODE_input_media_uploaded_video || f->media_type == CODE_input_media_uploaded_photo) { + out_int (100); + out_int (100); + } out_int (f->size); out_cstring ((void *)f->key, 32); out_cstring ((void *)f->init_iv, 32); @@ -1456,6 +1483,9 @@ void do_send_photo (int type, peer_id_t to_id, char *file_name) { if (f->media_type == CODE_input_media_uploaded_video && !f->encr) { f->media_type = CODE_input_media_uploaded_thumb_video; send_file_thumb (f); + } else if (f->media_type == CODE_input_media_uploaded_document && !f->encr) { + f->media_type = CODE_input_media_uploaded_thumb_document; + send_file_thumb (f); } else { send_part (f); } diff --git a/structures.c b/structures.c index 2e7788f..08561c9 100644 --- a/structures.c +++ b/structures.c @@ -513,6 +513,34 @@ void fetch_video (struct video *V) { V->h = fetch_int (); } +void fetch_audio (struct audio *V) { + memset (V, 0, sizeof (*V)); + unsigned x = fetch_int (); + V->id = fetch_long (); + if (x == CODE_audio_empty) { return; } + V->access_hash = fetch_long (); + V->user_id = fetch_int (); + V->date = fetch_int (); + V->duration = fetch_int (); + V->size = fetch_int (); + V->dc_id = fetch_int (); +} + +void fetch_document (struct document *V) { + memset (V, 0, sizeof (*V)); + unsigned x = fetch_int (); + V->id = fetch_long (); + if (x == CODE_document_empty) { return; } + V->access_hash = fetch_long (); + V->user_id = fetch_int (); + V->date = fetch_int (); + V->caption = fetch_str_dup (); + V->mime_type = fetch_str_dup (); + V->size = fetch_int (); + fetch_photo_size (&V->thumb); + V->dc_id = fetch_int (); +} + void fetch_message_action (struct message_action *M) { memset (M, 0, sizeof (*M)); unsigned x = fetch_int (); @@ -585,6 +613,12 @@ void fetch_message_media (struct message_media *M) { case CODE_message_media_video: fetch_video (&M->video); break; + case CODE_message_media_audio: + fetch_audio (&M->audio); + break; + case CODE_message_media_document: + fetch_document (&M->document); + break; case CODE_message_media_geo: fetch_geo (&M->geo); break; @@ -646,10 +680,63 @@ void fetch_message_media_encrypted (struct message_media *M) { fetch_str (l); // thumb fetch_int (); // thumb_w fetch_int (); // thumb_h + M->encr_video.duration = fetch_int (); M->encr_video.w = fetch_int (); M->encr_video.h = fetch_int (); M->encr_video.size = fetch_int (); - M->encr_video.duration = fetch_int (); + + l = prefetch_strlen (); + assert (l > 0); + M->encr_video.key = malloc (32); + memset (M->encr_photo.key, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); + } + M->encr_video.iv = malloc (32); + l = prefetch_strlen (); + assert (l > 0); + memset (M->encr_video.iv, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32); + } + break; + case CODE_decrypted_message_media_audio: + M->type = x; + M->encr_audio.duration = fetch_int (); + M->encr_audio.size = fetch_int (); + + l = prefetch_strlen (); + assert (l > 0); + M->encr_video.key = malloc (32); + memset (M->encr_photo.key, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.key + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.key, fetch_str (l) + (l - 32), 32); + } + M->encr_video.iv = malloc (32); + l = prefetch_strlen (); + assert (l > 0); + memset (M->encr_video.iv, 0, 32); + if (l <= 32) { + memcpy (M->encr_video.iv + (32 - l), fetch_str (l), l); + } else { + memcpy (M->encr_video.iv, fetch_str (l) + (l - 32), 32); + } + break; + case CODE_decrypted_message_media_document: + M->type = x; + l = prefetch_strlen (); + fetch_str (l); // thumb + fetch_int (); // thumb_w + fetch_int (); // thumb_h + M->encr_document.file_name = fetch_str_dup (); + M->encr_document.mime_type = fetch_str_dup (); + M->encr_video.size = fetch_int (); l = prefetch_strlen (); assert (l > 0); @@ -828,6 +915,7 @@ void fetch_encrypted_message (struct message *M) { unsigned sx = x; M->id = fetch_long (); peer_id_t chat = MK_ENCR_CHAT (fetch_int ()); + M->from_id = MK_USER (our_id); M->to_id = chat; peer_t *P = user_chat_get (chat); M->flags &= ~(FLAG_EMPTY | FLAG_DELETED); @@ -874,7 +962,9 @@ void fetch_encrypted_message (struct message *M) { fetch_message_media_encrypted (&M->media); } else { assert (fetch_int () == (int)CODE_decrypted_message_action_set_message_t_t_l); + M->action.type = CODE_decrypted_message_action_set_message_t_t_l; P->encr_chat.ttl = fetch_int (); + M->action.ttl = P->encr_chat.ttl; M->service = 1; } in_ptr = save_in_ptr; @@ -1029,10 +1119,18 @@ void free_video (struct video *V) { free_photo_size (&V->thumb); } +void free_document (struct document *D) { + if (!D->access_hash) { return; } + free (D->caption); + free (D->mime_type); + free_photo_size (&D->thumb); +} + void free_message_media (struct message_media *M) { switch (M->type) { case CODE_message_media_empty: case CODE_message_media_geo: + case CODE_message_media_audio: return; case CODE_message_media_photo: free_photo (&M->photo); @@ -1045,17 +1143,19 @@ void free_message_media (struct message_media *M) { free (M->first_name); free (M->last_name); return; + case CODE_message_media_document: + free_document (&M->document); + return; case CODE_message_media_unsupported: free (M->data); return; case CODE_decrypted_message_media_photo: + case CODE_decrypted_message_media_video: + case CODE_decrypted_message_media_audio: + case CODE_decrypted_message_media_document: free (M->encr_photo.key); free (M->encr_photo.iv); return; - case CODE_decrypted_message_media_video: - free (M->encr_video.key); - free (M->encr_video.iv); - return; case 0: break; default: diff --git a/structures.h b/structures.h index fe34654..5474c4e 100644 --- a/structures.h +++ b/structures.h @@ -76,10 +76,10 @@ struct encr_photo { int size; int key_fingerprint; - int w; - int h; unsigned char *key; unsigned char *iv; + int w; + int h; }; struct encr_video { @@ -89,13 +89,38 @@ struct encr_video { int size; int key_fingerprint; + unsigned char *key; + unsigned char *iv; int w; int h; + int duration; +}; + +struct encr_audio { + long long id; + long long access_hash; + int dc_id; + int size; + int key_fingerprint; + unsigned char *key; unsigned char *iv; int duration; }; +struct encr_document { + long long id; + long long access_hash; + int dc_id; + int size; + int key_fingerprint; + + unsigned char *key; + unsigned char *iv; + char *file_name; + char *mime_type; +}; + struct encr_file { char *filename; unsigned char *key; @@ -197,15 +222,37 @@ struct video { long long access_hash; int user_id; int date; + int size; + int dc_id; + struct photo_size thumb; char *caption; int duration; - int size; - struct photo_size thumb; - int dc_id; int w; int h; }; +struct audio { + long long id; + long long access_hash; + int user_id; + int date; + int size; + int dc_id; + int duration; +}; + +struct document { + long long id; + long long access_hash; + int user_id; + int date; + int size; + int dc_id; + struct photo_size thumb; + char *caption; + char *mime_type; +}; + struct message_action { int type; union { @@ -217,6 +264,7 @@ struct message_action { char *new_title; struct photo photo; int user; + int ttl; }; }; @@ -225,6 +273,8 @@ struct message_media { union { struct photo photo; struct video video; + struct audio audio; + struct document document; struct geo geo; struct { char *phone; @@ -234,6 +284,8 @@ struct message_media { }; struct encr_photo encr_photo; struct encr_video encr_video; + struct encr_audio encr_audio; + struct encr_document encr_document; struct encr_file encr_file; void *data; };