From 1c0ba265f0e8428caa23a39f65561a423b7eaed3 Mon Sep 17 00:00:00 2001 From: Vysheng Date: Mon, 21 Oct 2013 22:24:31 +0400 Subject: [PATCH] Support for sending photos. Some fixed bugs. Slightly changed interface --- interface.c | 46 +++++++++++++-- interface.h | 7 +++ mtproto-client.c | 57 ++++++++++++++++--- queries.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++- queries.h | 3 + 5 files changed, 241 insertions(+), 15 deletions(-) diff --git a/interface.c b/interface.c index dbef70f..a246954 100644 --- a/interface.c +++ b/interface.c @@ -33,6 +33,8 @@ char *commands[] = { "stats", "history", "dialog_list", + "send_photo", + "send_video", 0 }; int commands_flags[] = { @@ -42,6 +44,8 @@ int commands_flags[] = { 07, 072, 07, + 0732, + 0732, }; char *a = 0; @@ -219,6 +223,22 @@ void interpreter (char *line UU) { if (*q && index < user_num + chat_num) { do_send_message (Peers[index], q); } + } else if (!memcmp (line, "send_photo", 10)) { + char *q = line + 10; + int len; + char *text = get_token (&q, &len); + int index = 0; + while (index < user_num + chat_num && (!Peers[index]->print_name || strncmp (Peers[index]->print_name, text, len))) { + index ++; + } + if (index < user_num + chat_num) { + int len = 0; + char *f = get_token (&q, &len); + if (len > 0) { + do_send_photo (CODE_input_media_uploaded_photo, + Peers[index]->id, strndup (f, len)); + } + } } else if (!memcmp (line, "history", 7)) { char *q = line + 7; int len; @@ -380,7 +400,7 @@ void pop_color (void) { assert (color_stack_pos > 0); color_stack_pos --; if (color_stack_pos >= 1) { - printf ("%s", color_stack[color_stack_pos] - 1); + printf ("%s", color_stack[color_stack_pos - 1]); } else { printf ("%s", COLOR_NORMAL); } @@ -391,7 +411,11 @@ void print_media (struct message_media *M) { case CODE_message_media_empty: return; case CODE_message_media_photo: - printf ("[photo]"); + if (M->photo.caption && strlen (M->photo.caption)) { + printf ("[photo %s]", M->photo.caption); + } else { + printf ("[photo]"); + } return; case CODE_message_media_video: printf ("[video]"); @@ -466,7 +490,11 @@ void print_message (struct message *M) { printf (" "); print_user_name (M->to_id, user_chat_get (M->to_id)); push_color (COLOR_GREEN); - printf (" <<< "); + if (M->unread) { + printf (" <<< "); + } else { + printf (" ««« "); + } } else { push_color (COLOR_BLUE); print_date (M->date); @@ -474,7 +502,11 @@ void print_message (struct message *M) { printf (" "); print_user_name (M->from_id, user_chat_get (M->from_id)); push_color (COLOR_BLUE); - printf (" >>> "); + if (M->unread) { + printf (" >>> "); + } else { + printf (" »»» "); + } } } else { push_color (COLOR_MAGENTA); @@ -489,7 +521,11 @@ void print_message (struct message *M) { } else { push_color (COLOR_BLUE); } - printf (" >>> "); + if (M->unread) { + printf (" >>> "); + } else { + printf (" »»» "); + } } if (M->message && strlen (M->message)) { printf ("%s", M->message); diff --git a/interface.h b/interface.h index eacf061..ecb94f6 100644 --- a/interface.h +++ b/interface.h @@ -22,4 +22,11 @@ void hexdump (int *in_ptr, int *in_end); struct message; void print_message (struct message *M); +void print_chat_name (int id, union user_chat *C); +void print_user_name (int id, union user_chat *U); +//void print_media (struct message_media *M); +void pop_color (void); +void push_color (const char *color); +void print_start (void); +void print_end (void); #endif diff --git a/mtproto-client.c b/mtproto-client.c index d7bde57..afa7767 100644 --- a/mtproto-client.c +++ b/mtproto-client.c @@ -645,15 +645,24 @@ void work_update (struct connection *c UU, long long msg_id UU) { } } fetch_int (); //pts + print_start (); + push_color (COLOR_YELLOW); + printf ("%d messages marked as read\n", n); + pop_color (); + print_end (); } break; case CODE_update_user_typing: { int id = fetch_int (); union user_chat *U = user_chat_get (id); - if (U) { - rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is typing....\n" COLOR_NORMAL, U->user.first_name, U->user.last_name); - } + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (id, U); + printf (" is typing....\n"); + pop_color (); + print_end (); } break; case CODE_update_chat_user_typing: @@ -662,9 +671,15 @@ void work_update (struct connection *c UU, long long msg_id UU) { int id = fetch_int (); union user_chat *C = user_chat_get (-chat_id); union user_chat *U = user_chat_get (id); - if (U && C) { - rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is typing in chat %s....\n" COLOR_NORMAL, U->user.first_name, U->user.last_name, C->chat.title); - } + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (id, U); + printf (" is typing in chat "); + print_chat_name (-chat_id, C); + printf ("....\n"); + pop_color (); + print_end (); } break; case CODE_update_user_status: @@ -673,7 +688,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { union user_chat *U = user_chat_get (user_id); if (U) { fetch_user_status (&U->user.status); - rprintf (COLOR_YELLOW "User " COLOR_RED "%s %s" COLOR_YELLOW " is now %s\n" COLOR_NORMAL, U->user.first_name, U->user.last_name, (U->user.status.online > 0) ? "online" : "offline"); + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (user_id, U); + printf (" is now "); + printf ("%s\n", (U->user.status.online > 0) ? "online" : "offline"); + pop_color (); + print_end (); } else { struct user_status t; fetch_user_status (&t); @@ -686,11 +708,20 @@ void work_update (struct connection *c UU, long long msg_id UU) { union user_chat *UC = user_chat_get (user_id); if (UC) { struct user *U = &UC->user; + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (user_id, UC); if (U->first_name) { free (U->first_name); } - if (U->last_name) { free (U->first_name); } - if (U->print_name) { free (U->first_name); } + if (U->last_name) { free (U->last_name); } + if (U->print_name) { free (U->print_name); } U->first_name = fetch_str_dup (); U->last_name = fetch_str_dup (); + printf (" changed name to "); + print_user_name (user_id, UC); + printf ("\n"); + pop_color (); + print_end (); if (!strlen (U->first_name)) { if (!strlen (U->last_name)) { U->print_name = strdup ("none"); @@ -722,6 +753,14 @@ void work_update (struct connection *c UU, long long msg_id UU) { union user_chat *UC = user_chat_get (user_id); if (UC) { struct user *U = &UC->user; + + print_start (); + push_color (COLOR_YELLOW); + printf ("User "); + print_user_name (user_id, UC); + printf (" updated profile photo\n"); + pop_color (); + print_end (); unsigned y = fetch_int (); if (y == CODE_user_profile_photo_empty) { U->photo_big.dc = -2; diff --git a/queries.c b/queries.c index f3139c0..7c4b503 100644 --- a/queries.c +++ b/queries.c @@ -1,7 +1,12 @@ +#define _FILE_OFFSET_BITS 64 #include #include #include #include +#include +#include +#include +#include #include "include.h" #include "mtproto-client.h" @@ -57,8 +62,11 @@ struct query *send_query (struct dc *DC, int ints, void *data, struct query_meth logprintf ( "Msg_id is %lld\n", q->msg_id); } q->methods = methods; + q->DC = DC; if (queries_tree) { - logprintf ( "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); + if (verbosity >= 2) { + logprintf ( "%lld %lld\n", q->msg_id, queries_tree->x->msg_id); + } } queries_tree = tree_insert_query (queries_tree, q, lrand48 ()); @@ -581,3 +589,136 @@ void do_get_dialog_list (void) { out_int (1000); send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &get_dialogs_methods, 0); } + +struct send_file { + int fd; + long long size; + long long offset; + int part_num; + int part_size; + long long id; + int to_id; + int media_type; + char *file_name; +}; + +void out_peer_id (int id) { + union user_chat *U = user_chat_get (id); + if (id < 0) { + out_int (CODE_input_peer_chat); + out_int (-id); + } else { + if (U && U->user.access_hash) { + out_int (CODE_input_peer_foreign); + out_int (id); + out_long (U->user.access_hash); + } else { + out_int (CODE_input_peer_contact); + out_int (id); + } + } +} + +void send_part (struct send_file *f); +int send_file_part_on_answer (struct query *q) { + assert (fetch_int () == (int)CODE_bool_true); + send_part (q->extra); + return 0; +} + +int send_file_on_answer (struct query *q UU) { + assert (fetch_int () == (int)CODE_messages_stated_message); + struct message *M = fetch_alloc_message (); + assert (fetch_int () == CODE_vector); + int n, i; + n = fetch_int (); + for (i = 0; i < n; i++) { + fetch_alloc_chat (); + } + assert (fetch_int () == CODE_vector); + n = fetch_int (); + for (i = 0; i < n; i++) { + fetch_alloc_user (); + } + fetch_int (); // pts + fetch_int (); // seq + print_message (M); + return 0; +} + +struct query_methods send_file_part_methods = { + .on_answer = send_file_part_on_answer +}; + +struct query_methods send_file_methods = { + .on_answer = send_file_on_answer +}; + +void send_part (struct send_file *f) { + if (f->fd >= 0) { + clear_packet (); + out_int (CODE_upload_save_file_part); + out_long (f->id); + out_int (f->part_num ++); + static char buf[512 << 10]; + int x = read (f->fd, buf, f->part_size); + assert (x > 0); + out_cstring (buf, x); + f->offset += x; + logprintf ("offset=%lld size=%lld\n", f->offset, f->size); + if (f->offset == f->size) { + close (f->fd); + f->fd = -1; + } + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_part_methods, f); + } else { + clear_packet (); + out_int (CODE_messages_send_media); + out_peer_id (f->to_id); + assert (f->media_type == CODE_input_media_uploaded_photo); + out_int (f->media_type); + out_int (CODE_input_file); + out_long (f->id); + out_int (f->part_num); + char *s = f->file_name + strlen (f->file_name); + while (s >= f->file_name && *s != '/') { s --;} + out_string (s + 1); + out_string (""); + out_long (-lrand48 () * (1ll << 32) - lrand48 ()); + send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &send_file_methods, 0); + free (f->file_name); + free (f); + } +} + +void do_send_photo (int type, int to_id, char *file_name) { + int fd = open (file_name, O_RDONLY); + if (fd < 0) { + rprintf ("No such file '%s'\n", file_name); + return; + } + struct stat buf; + fstat (fd, &buf); + long long size = buf.st_size; + if (size <= 0) { + rprintf ("File has zero length\n"); + close (fd); + return; + } + struct send_file *f = malloc (sizeof (*f)); + f->fd = fd; + f->size = size; + f->offset = 0; + f->part_num = 0; + f->part_size = (size / 1000 + 0x3ff) & ~0x3ff; + f->id = lrand48 () * (1ll << 32) + lrand48 (); + f->to_id = to_id; + f->media_type = type; + f->file_name = file_name; + if (f->part_size > (512 << 10)) { + close (fd); + rprintf ("Too big file. Maximal supported size is %d", (512 << 10) * 1000); + return; + } + send_part (f); +} diff --git a/queries.h b/queries.h index 84012aa..477cd9b 100644 --- a/queries.h +++ b/queries.h @@ -24,6 +24,7 @@ struct query { void *data; struct query_methods *methods; struct event_timer ev; + struct dc *DC; void *extra; }; @@ -49,4 +50,6 @@ union user_chat; void do_send_message (union user_chat *U, const char *msg); void do_get_history (union user_chat *U, int limit); void do_get_dialog_list (void); +void do_send_photo (int type, int to_id, char *file_name); + #endif