/* * Created by yuuta on 4/1/22. */ #include "tdutils.h" #include "logic.h" #include "log.h" #include "db.h" #include #include #include #include #include struct result { char id[32]; /* Title in selection */ char *title; /* Description in selection */ char *description; /* Text after sending */ char *text; char *url; }; static void cb_answer(bool successful, struct TdObject *result, struct TdError *error, void *cb_arg) { if (!successful) { LOGEV("Cannot answer inline request: %s.", error ? error->message_ : "(NULL)"); } } int handle_inline(struct TdUpdateNewInlineQuery *update) { struct result results[11]; memset(results, 0, sizeof(results)); sqlite3_stmt *stmt; int r; const bool query = update->query_; if ((r = sqlite3_prepare_v2(db, "SELECT i FROM stats WHERE user = ?", -1, &stmt, NULL))) { goto sql_err; sql_err: snprintf(results[0].id, 32, "e%d", r); char *msg = (char *) sqlite3_errstr(r); LOGEV("Cannot query: %s.", msg); results[0].title = "Error!"; results[0].text = msg; results[0].description = msg; if (stmt) sqlite3_finalize(stmt); goto answer; } if ((r = sqlite3_bind_int64(stmt, 1, update->sender_user_id_))) { goto sql_err; } char msg_stat[32]; int st; switch (r = sqlite3_step(stmt)) { case SQLITE_ROW: { st = sqlite3_column_int(stmt, 0); goto st_answer; st_answer: snprintf(msg_stat, 32, "我已经卖了 %d 句菜", st); results[0].title = "卖菜统计"; results[0].text = msg_stat; results[0].description = "点击发送卖菜统计"; snprintf(results[0].id, 32, "s%lld", update->sender_user_id_); break; } case SQLITE_DONE: { st = 0; goto st_answer; } default: { goto sql_err; } } sqlite3_finalize(stmt); stmt = NULL; if ((r = sqlite3_prepare_v2(db, query ? "SELECT id, t, url FROM says WHERE t LIKE ? LIMIT 10;" : "SELECT id, t, url FROM says ORDER BY RANDOM() LIMIT 10;", -1, &stmt, NULL))) { goto sql_err; } char *query_str = NULL; if (query) { const size_t raw_query_len = strlen(update->query_); if (!(query_str = calloc(raw_query_len + 3, sizeof(char)))) { r = errno; LOGEV("Cannot allocate memory: %s.", strerror(r)); sqlite3_finalize(stmt); return r; } sprintf(query_str, "%%%s%%", update->query_); if ((r = sqlite3_bind_text(stmt, 1, query_str, ((int) raw_query_len + 3), NULL))) { free(query_str); goto sql_err; } } int j = 1; goto step; step: switch (r = sqlite3_step(stmt)) { case SQLITE_ROW: { char *t = (char *) sqlite3_column_text(stmt, 1); char *url = (char *) sqlite3_column_text(stmt, 2); char *url1 = NULL; char *title = NULL; char *t1 = NULL; if (url && !(url1 = strdup(url))) { LOGEV("Cannot allocate memory: %s.", strerror(errno)); break; } if (!(title = strdup(t))) { LOGEV("Cannot allocate memory: %s.", strerror(errno)); break; } if (!(t1 = strdup(t))) { LOGEV("Cannot allocate memory: %s.", strerror(errno)); break; } results[j].title = title; snprintf(results[j].id, 32, "x_%d", sqlite3_column_int(stmt, 0)); results[j].text = t1; results[j].url = url1; results[j].description = url1; if ((++j) > 10) break; goto step; } case SQLITE_DONE: { break; } default: { goto sql_err; } } if (query_str) free(query_str); sqlite3_finalize(stmt); /* There must be a stat option. */ assert(results[0].title); goto answer; answer: { struct TdInputInlineQueryResultArticle *results_inline[11]; /* No need to memset(). Var 'i' will assure that. */ int i; for (i = 0; i < sizeof(results) / sizeof(struct result); i++) { struct result res = results[i]; if (!res.title) { break; } results_inline[i] = TdCreateObjectInputInlineQueryResultArticle( res.id, NULL, false, res.title, res.description, NULL, 0, 0, NULL, (struct TdInputMessageContent *) TdCreateObjectInputMessageText( TdCreateObjectFormattedText(res.text, (struct TdVectorTextEntity *) TdCreateObjectVectorObject(0, NULL)), true, false )); } td_send(TdCreateObjectAnswerInlineQuery(update->id_, false, (struct TdVectorInputInlineQueryResult *) TdCreateObjectVectorObject(i, (struct TdObject **) results_inline), 0, NULL, NULL, NULL), &cb_answer, NULL); for (i = 1 /* 0 is error message or stats */; i < sizeof(results) / sizeof(struct result); i++) { struct result res = results[i]; if (!res.title) { break; } free(res.title); if (res.url) free(res.url); free(res.text); } return r; } } int handle_inline_chosen(struct TdUpdateNewChosenInlineResult *update) { if (!update->result_id_ || update->result_id_[0] != 'x' || update->result_id_[1] != '_') return 0; int r; sqlite3_stmt *stmt = NULL; if ((r = sqlite3_prepare_v2(db, "UPDATE stats SET i = i + 1 WHERE user = ?;", -1, &stmt, NULL))) { goto sql_err; sql_err: LOGEV("Cannot change stat: %s.", sqlite3_errstr(r)); if (stmt) sqlite3_finalize(stmt); return r; } if ((r = sqlite3_bind_int64(stmt, 1, update->sender_user_id_))) { goto sql_err; } if ((r = sqlite3_step(stmt)) != SQLITE_DONE) { goto sql_err; } sqlite3_finalize(stmt); stmt = NULL; if (sqlite3_changes(db)) { return 0; } if ((r = sqlite3_prepare_v2(db, "INSERT INTO stats(user, i) VALUES(?, 1);", -1, &stmt, NULL))) { goto sql_err; } if ((r = sqlite3_bind_int64(stmt, 1, update->sender_user_id_))) { goto sql_err; } if ((r = sqlite3_step(stmt)) != SQLITE_DONE) { goto sql_err; } sqlite3_finalize(stmt); return 0; }