/* * Created by yuuta on 4/1/22. */ #include "log.h" #include "logic.h" #include "botd.h" #include "tdutils.h" #include #include #include #include #include #include #include struct refresh_session { bool running; long long chat_id; long long message_id; long long offset_message_id; unsigned int progress; unsigned int start; unsigned int end; unsigned int imported; }; static struct refresh_session current_session = { false, 0, 0, 0 }; static void refresh_get(void); static void send_msg(long long chat_id, long long message_id, char *text) { td_send(TdCreateObjectSendMessage(chat_id, /* chat_id */ 0, /* message_thread_id */ (struct TdMessageReplyTo *) TdCreateObjectMessageReplyToMessage(chat_id, message_id) /* reply_to */, TdCreateObjectMessageSendOptions(false, /* disable_notification */ false, /* from_background */ true, /* protect_content */ false, /* update_order_of_installed_sticker_sets */ NULL /* scheduling_state */, 0 /* sending_id */), NULL, (struct TdInputMessageContent *) TdCreateObjectInputMessageText( TdCreateObjectFormattedText(text, (struct TdVectorTextEntity *) TdCreateObjectVectorObject( 0, NULL) ), false, false)), NULL, NULL); } static void send_administrative_msg(char *text) { send_msg(current_session.chat_id, current_session.message_id, text); } static void cb_store(bool succ) { if (succ && current_session.running) current_session.imported++; } static void cb_refresh_mlink(bool successful, struct TdObject *result, struct TdError *error, void *cb_arg) { if (!successful) { char msg[512]; snprintf(msg, 512, "Cannot get message link info: %d (%s)", error ? error->code_ : -1, error ? error->message_ : "NULL"); send_administrative_msg(msg); current_session.running = false; return; } struct TdMessageLinkInfo *info = (struct TdMessageLinkInfo *) result; if (!info->message_) { refresh_get(); return; } LOGDV("%lld", info->message_->id_); store(info->message_, &cb_store); refresh_get(); } static void cb_refresh_link(bool successful, struct TdObject *result, struct TdError *error, void *cb_arg) { if (!successful) { char msg[512]; snprintf(msg, 512, "Cannot get link: %d (%s)", error ? error->code_ : -1, error ? error->message_ : "NULL"); send_administrative_msg(msg); current_session.running = false; return; } struct TdInternalLinkType *type = (struct TdInternalLinkType *) result; if (type->ID != CODE_InternalLinkTypeMessage) { refresh_get(); return; } struct TdInternalLinkTypeMessage *m = (struct TdInternalLinkTypeMessage *) type; td_send(TdCreateObjectGetMessageLinkInfo(m->url_), &cb_refresh_mlink, NULL); } static void refresh_prog_report(char msg[512]) { snprintf(msg, 512, "Result report:\n" "Progress: %u / %u. Imported %u.", current_session.progress - current_session.start, 1 + current_session.end - current_session.start, current_session.imported); } static void refresh_get(void) { if (!current_session.running) return; if (current_session.progress > current_session.end) { char m[1024] = "Done. "; refresh_prog_report(&m[6]); send_administrative_msg(m); current_session.running = false; return; } char url[64]; sprintf(url, "https://t.me/c/1794945713/%u", current_session.progress++); LOGDV("Get %s", url); td_send(TdCreateObjectGetInternalLinkType(url), &cb_refresh_link, NULL); } static void cmd_start(struct TdMessage *msg, unsigned int start, unsigned int end) { if (current_session.running) { send_msg(msg->chat_id_, msg->id_, "A refresh is already in progress."); return; } current_session.running = true; current_session.message_id = msg->id_; current_session.chat_id = msg->chat_id_; current_session.offset_message_id = 0; current_session.progress = start; current_session.end = end; current_session.start = start; current_session.imported = 0; send_administrative_msg("Refreshing ..."); refresh_get(); } static void cmd_status(struct TdMessage *msg) { char m[1024]; if (current_session.running) { snprintf(m, 1024, "A refresh task is running. "); refresh_prog_report(&m[27]); } else { snprintf(m, 1024, "Refresh is not running."); } send_msg(msg->chat_id_, msg->id_, m); } static void cmd_stop(struct TdMessage *msg) { if (!current_session.running) { send_msg(msg->chat_id_, msg->id_, "Refresh is not running."); return; } current_session.running = false; char m[1024] = "Stopped. "; refresh_prog_report(&m[9]); send_msg(msg->chat_id_, msg->id_, m); } void refresh(struct TdMessage *msg) { assert(msg->content_->ID == CODE_MessageText); char *token = strtok(((struct TdMessageText *) msg->content_)->text_->text_, " "); unsigned int i = 0; unsigned int action = 0; unsigned int start = 0; unsigned int end = 0; while (token) { LOGDV("%u %s", i, token); switch (i++) { case 0: { break; } case 1: { /* 0: /refresh */ if (!strcmp(token, "start")) { action = 1; } else if (!strcmp(token, "status")) { action = 2; } else if (!strcmp(token, "stop")) { action = 3; } else { send_msg(msg->chat_id_, msg->id_, "Invalid command."); return; } break; } case 2: { if (action != 1) { send_msg(msg->chat_id_, msg->id_, "Invalid argument."); return; } goto parse_range; parse_range: { char *endptr; uintmax_t num = strtoumax(token, &endptr, 10); if (strcmp(endptr, "") != 0 || (num == UINTMAX_MAX && errno == ERANGE) || num > UINT_MAX || num <= 0) { send_msg(msg->chat_id_, msg->id_, "Invalid range."); return; } if (!start) start = (unsigned int) num; else end = (unsigned int) num; } break; } case 3: { if (action != 1) { send_msg(msg->chat_id_, msg->id_, "Invalid argument."); return; } goto parse_range; } default: { send_msg(msg->chat_id_, msg->id_, "Invalid argument."); return; } } token = strtok(NULL, " "); } switch (action) { case 1: { if (!start || !end || end < start) { send_msg(msg->chat_id_, msg->id_, "Usage: /refresh start [from] [to]"); return; } cmd_start(msg, start, end); break; } case 2: { cmd_status(msg); break; } case 3: { cmd_stop(msg); break; } default: { send_msg(msg->chat_id_, msg->id_, "Invalid argument."); break; } } }