diff --git a/interface.c b/interface.c index 6062465..e5f8281 100644 --- a/interface.c +++ b/interface.c @@ -68,6 +68,12 @@ char *commands[] = { "user_info", "fwd", "rename_chat", + "load_photo", + "view_photo", + "load_video_thumb", + "view_video_thumb", + "load_video", + "view_video", "show_license", 0 }; @@ -86,6 +92,12 @@ int commands_flags[] = { 072, 074, 07, + 07, + 07, + 07, + 07, + 07, + 07, }; char *a = 0; @@ -356,6 +368,84 @@ void interpreter (char *line UU) { } } } + } else if (!memcmp (line, "load_photo ", 10)) { + char *q = line + 10; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { + do_load_photo (&M->media.photo, 1); + } + } + } + } else if (!memcmp (line, "view_photo ", 10)) { + char *q = line + 10; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_photo) { + do_load_photo (&M->media.photo, 2); + } + } + } + } else if (!memcmp (line, "load_video_thumb ", 16)) { + char *q = line + 16; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video_thumb (&M->media.video, 1); + } + } + } + } else if (!memcmp (line, "view_video_thumb ", 16)) { + char *q = line + 16; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video_thumb (&M->media.video, 2); + } + } + } + } else if (!memcmp (line, "load_video ", 10)) { + char *q = line + 10; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video (&M->media.video, 1); + } + } + } + } else if (!memcmp (line, "view_video ", 10)) { + char *q = line + 10; + int len = 0; + char *f = get_token (&q, &len); + if (f) { + int num = atoi (f); + if (num > 0) { + struct message *M = message_get (num); + if (M && !M->service && M->media.type == (int)CODE_message_media_video) { + do_load_video (&M->media.video, 2); + } + } + } } else if (!memcmp (line, "chat_info", 9)) { char *q = line + 10; int len; diff --git a/loop.c b/loop.c index 0aa9fa1..63a4899 100644 --- a/loop.c +++ b/loop.c @@ -244,7 +244,7 @@ int loop (void) { } write_auth_file (); - + fflush (stdin); fflush (stdout); fflush (stderr); diff --git a/queries.c b/queries.c index 872b9d8..872ba4e 100644 --- a/queries.c +++ b/queries.c @@ -36,6 +36,7 @@ #include "structures.h" #include "interface.h" +char *get_downloads_directory (void); int verbosity; #define QUERY_TIMEOUT 0.3 @@ -1059,3 +1060,162 @@ void do_get_user_list_info_silent (int num, int *list) { } send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &user_list_info_silent_methods, 0); } + +struct download { + int offset; + int size; + long long volume; + long long secret; + long long access_hash; + int local_id; + int dc; + int next; + int fd; + char *name; + long long id; +}; + + +void end_load (struct download *D) { + close (D->fd); + if (D->next == 1) { + logprintf ("Done: %s\n", D->name); + } else if (D->next == 2) { + static char buf[1000]; + sprintf (buf, "xdg-open %s", D->name); + int x = system (buf); + if (x < 0) { + logprintf ("Can not open image viewer: %m\n"); + logprintf ("Image is at %s\n", D->name); + } + } + free (D->name); + free (D); +} + +void load_next_part (struct download *D); +int download_on_answer (struct query *q) { + assert (fetch_int () == (int)CODE_upload_file); + unsigned x = fetch_int (); + struct download *D = q->extra; + if (D->fd == -1) { + static char buf[100]; + sprintf (buf, "%s/tmp_%ld_%ld", get_downloads_directory (), lrand48 (), lrand48 ()); + int l = strlen (buf); + switch (x) { + case CODE_storage_file_unknown: + break; + case CODE_storage_file_jpeg: + sprintf (buf + l, "%s", ".jpg"); + break; + case CODE_storage_file_gif: + sprintf (buf + l, "%s", ".gif"); + break; + case CODE_storage_file_png: + sprintf (buf + l, "%s", ".png"); + break; + case CODE_storage_file_mp3: + sprintf (buf + l, "%s", ".mp3"); + break; + case CODE_storage_file_mov: + sprintf (buf + l, "%s", ".mov"); + break; + case CODE_storage_file_partial: + sprintf (buf + l, "%s", ".part"); + break; + case CODE_storage_file_mp4: + sprintf (buf + l, "%s", ".mp4"); + break; + case CODE_storage_file_webp: + sprintf (buf + l, "%s", ".webp"); + break; + } + D->name = strdup (buf); + D->fd = open (D->name, O_CREAT | O_WRONLY, 0640); + } + fetch_int (); // mtime + int len = prefetch_strlen (); + assert (len >= 0); + assert (write (D->fd, fetch_str (len), len) == len); + D->offset += len; + if (D->offset < D->size) { + load_next_part (D); + return 0; + } else { + end_load (D); + return 0; + } +} + +struct query_methods download_methods = { + .on_answer = download_on_answer +}; + +void load_next_part (struct download *D) { + clear_packet (); + out_int (CODE_upload_get_file); + if (!D->id) { + out_int (CODE_input_file_location); + out_long (D->volume); + out_int (D->local_id); + out_long (D->secret); + } else { + out_int (CODE_input_video_file_location); + out_long (D->id); + out_long (D->access_hash); + } + out_int (D->offset); + out_int (1 << 14); + send_query (DC_list[D->dc], packet_ptr - packet_buffer, packet_buffer, &download_methods, D); + //send_query (DC_working, packet_ptr - packet_buffer, packet_buffer, &download_methods, D); +} + +void do_load_photo_size (struct photo_size *P, int next) { + assert (P); + assert (next); + struct download *D = malloc (sizeof (*D)); + D->id = 0; + D->offset = 0; + D->size = P->size; + D->volume = P->loc.volume; + D->dc = P->loc.dc; + D->local_id = P->loc.local_id; + D->secret = P->loc.secret; + D->next = next; + D->name = 0; + D->fd = -1; + load_next_part (D); +} + +void do_load_photo (struct photo *photo, int next) { + if (!photo->sizes_num) { return; } + int max = -1; + int maxi = 0; + int i; + for (i = 0; i < photo->sizes_num; i++) { + if (photo->sizes[i].w + photo->sizes[i].h > max) { + max = photo->sizes[i].w + photo->sizes[i].h; + maxi = i; + } + } + do_load_photo_size (&photo->sizes[maxi], next); +} + +void do_load_video_thumb (struct video *video, int next) { + do_load_photo_size (&video->thumb, next); +} + +void do_load_video (struct video *V, int next) { + assert (V); + assert (next); + struct download *D = malloc (sizeof (*D)); + D->offset = 0; + D->size = V->size; + D->id = V->id; + D->access_hash = V->access_hash; + D->dc = V->dc_id; + D->next = next; + D->name = 0; + D->fd = -1; + load_next_part (D); +} diff --git a/queries.h b/queries.h index 18f74bd..39fb6cd 100644 --- a/queries.h +++ b/queries.h @@ -79,4 +79,10 @@ void do_get_user_info (union user_chat *user); void do_forward_message (union user_chat *U, int n); void do_rename_chat (union user_chat *U, char *name); +struct photo; +struct video; +void do_load_photo (struct photo *photo, int next); +void do_load_video_thumb (struct video *video, int next); +void do_load_video (struct video *V, int next); + #endif diff --git a/structures.c b/structures.c index 1926525..a6cdcca 100644 --- a/structures.c +++ b/structures.c @@ -348,7 +348,9 @@ void fetch_photo_size (struct photo_size *S) { if (x == CODE_photo_size) { S->size = fetch_int (); } else { - S->data = fetch_str_dup (); + S->size = prefetch_strlen (); + S->data = malloc (S->size); + memcpy (S->data, fetch_str (S->size), S->size); } } }