Files
blog_tgbot/main.c
T

127 lines
3.1 KiB
C

#include <curl/curl.h>
#include <curl/easy.h>
#include <stdint.h>
#include <stdio.h>
#include <yyjson.h>
#define API_LEN 256
#define URL_LEN 512
#define TEXT_LEN 4096
typedef struct tgbot {
CURL *curl;
char api[API_LEN];
int64_t offset;
} tgbot;
typedef struct tgmessage {
int64_t chat_id;
const char *text;
} tgmessage;
void send_message(tgbot *bot, tgmessage *message) {
char url[512];
char *encoded_text = curl_easy_escape(bot->curl, message->text, 0);
snprintf(url, sizeof(url), "%ssendMessage?chat_id=%ld&text=%s", bot->api,
message->chat_id, encoded_text);
curl_easy_setopt(bot->curl, CURLOPT_URL, url);
curl_easy_perform(bot->curl);
curl_free(encoded_text);
}
size_t write_cb(void *ptr, size_t size, size_t nmemb, char *data) {
strncat(data, ptr, size * nmemb);
return size * nmemb;
}
int handle_updates(tgbot *bot) {
/* Prepare our update */
char url[URL_LEN] = {0};
char response[TEXT_LEN] = {0};
snprintf(url, sizeof(url), "%sgetUpdates?timeout=30&offset=%ld", bot->api,
bot->offset + 1);
/* A little bit higher than 30s polling */
curl_easy_setopt(bot->curl, CURLOPT_TIMEOUT, 35L);
curl_easy_setopt(bot->curl, CURLOPT_URL, url);
curl_easy_setopt(bot->curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(bot->curl, CURLOPT_WRITEDATA, response);
int res = curl_easy_perform(bot->curl);
if (res != CURLE_OK) {
return -1;
}
/* Print json response */
fprintf(stdout, "%s\n", response);
/* Let's parse json */
yyjson_doc *doc = yyjson_read(response, strlen(response), 0);
yyjson_val *root = yyjson_doc_get_root(doc);
yyjson_val *ok = yyjson_obj_get(root, "ok");
if (yyjson_get_bool(ok) != true) {
yyjson_doc_free(doc);
return -1;
}
/* Parse result */
yyjson_val *result = yyjson_obj_get(root, "result");
/* result is an array, so iterate over it */
yyjson_val *a_result;
size_t idx, max;
yyjson_arr_foreach(result, idx, max, a_result) {
/* Update offset */
yyjson_val *update_id = yyjson_obj_get(a_result, "update_id");
bot->offset = yyjson_get_sint(update_id);
/* Get message */
yyjson_val *message = yyjson_obj_get(a_result, "message");
yyjson_val *text = yyjson_obj_get(message, "text");
yyjson_val *chat = yyjson_obj_get(message, "chat");
yyjson_val *id = yyjson_obj_get(chat, "id");
/* Echo message */
tgmessage msg = {
.chat_id = yyjson_get_sint(id),
.text = yyjson_get_str(text),
};
send_message(bot, &msg);
}
return 0;
}
int main(int argc, char **argv) {
if (argc < 2) {
fprintf(stderr, "Usage: %s <token>", argv[0]);
return -1;
}
/* Initialize curl */
curl_global_init(CURL_GLOBAL_ALL);
/* Initialize our bot struct */
tgbot bot = {
.offset = 0,
.curl = curl_easy_init(),
};
/* Retrieve bot token from args */
snprintf(bot.api, sizeof(bot.api), "https://api.telegram.org/bot%s/",
argv[1]);
/* Bot loop */
int err = 0;
while (!err) {
/* Find a better way to deal with CTRL-C, etc... and cleanup */
err = handle_updates(&bot);
}
/* Cleanup */
curl_easy_cleanup(bot.curl);
curl_global_cleanup();
}