Add fedi_notifs
This commit is contained in:
parent
d84c9ad364
commit
cf1529b6c1
5
Makefile
5
Makefile
|
@ -1,12 +1,17 @@
|
|||
all:
|
||||
gcc -o fedi_post fedi_post.c $(shell pkg-config --cflags --libs r_util r_io libcurl)
|
||||
gcc -o fedi_notifs fedi_notifs.c $(shell pkg-config --cflags --libs r_util r_io libcurl libjson)
|
||||
|
||||
clean:
|
||||
rm fedi_post
|
||||
rm fedi_notifs
|
||||
|
||||
install:
|
||||
cp fedi_post /usr/bin
|
||||
cp fedi_notifs /usr/bin
|
||||
chmod 755 /usr/bin/fedi_post
|
||||
chmod 755 /usr/bin/fedi_notifs
|
||||
|
||||
uninstall:
|
||||
rm /usr/bin/fedi_post
|
||||
rm /usr/bin/fedi_notifs
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
* libcurl
|
||||
* radare2 (build and install it from https://github.com/radareorg/radare2)
|
||||
* libjson (https://github.com/Cebtenzzre/libjson)
|
||||
|
||||
|
||||
# Build
|
||||
|
@ -37,8 +38,9 @@ sdb ~/.fedi_tools.sdb password=<your-password>
|
|||
|
||||
# The tools
|
||||
|
||||
So far there is only `fedi_post` which let's you make a post on fedi.
|
||||
You can use it like this:
|
||||
So far there are only `fedi_post` and `fedi_notifs`.
|
||||
The latter fetches your notifications for you, nothing too exciting.
|
||||
The former let's you make a post on fedi. You can use it like this:
|
||||
|
||||
```sh
|
||||
fedi_post <text-file-containing-your-post>
|
||||
|
|
273
fedi_notifs.c
Normal file
273
fedi_notifs.c
Normal file
|
@ -0,0 +1,273 @@
|
|||
/* fedi_tools - GPL - Copyright 2023 - condret */
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <r_io.h>
|
||||
#include <r_util.h>
|
||||
#include <json.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
__attribute__((constructor)) void foo(void) {
|
||||
curl_global_init (CURL_GLOBAL_ALL);
|
||||
}
|
||||
|
||||
__attribute__((destructor)) void bla(void) {
|
||||
curl_global_cleanup ();
|
||||
}
|
||||
|
||||
typedef struct fedi_notifs_config_t {
|
||||
char *instance;
|
||||
char *creds;
|
||||
} FediNotifsCFG;
|
||||
|
||||
// workaround for a bug in sdb
|
||||
static Sdb *load_sdb (char *path) {
|
||||
Sdb *ret = sdb_new0 ();
|
||||
Sdb *on_disk = sdb_new0 ();
|
||||
if (sdb_open (on_disk, path) < 0) {
|
||||
sdb_free (ret);
|
||||
sdb_free (on_disk);
|
||||
return NULL;
|
||||
}
|
||||
sdb_copy (on_disk, ret);
|
||||
sdb_close (on_disk);
|
||||
sdb_free (on_disk);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FediNotifsCFG *get_cfg () {
|
||||
FediNotifsCFG *fncfg;
|
||||
if (!(fncfg = R_NEW0 (FediNotifsCFG))) {
|
||||
return NULL;
|
||||
}
|
||||
char *config_path = r_file_home (".fedi_tools.sdb");
|
||||
if (!config_path) {
|
||||
free (fncfg);
|
||||
return NULL;
|
||||
}
|
||||
Sdb *db = load_sdb (config_path);
|
||||
if (!db) {
|
||||
eprintf ("couldn't open %s :(\n", config_path);
|
||||
sdb_free (db);
|
||||
free (config_path);
|
||||
free (fncfg);
|
||||
return NULL;
|
||||
}
|
||||
bool fail = false;
|
||||
if (!sdb_exists (db, "instance")) {
|
||||
eprintf ("'instance' is not set in %s :(\n", config_path);
|
||||
fail = true;
|
||||
}
|
||||
if (!sdb_exists (db, "user")) {
|
||||
eprintf ("'user' is not set in %s :(\n", config_path);
|
||||
fail = true;
|
||||
}
|
||||
if (!sdb_exists (db, "password")) {
|
||||
eprintf ("'password' is not set in %s :(\n", config_path);
|
||||
fail = true;
|
||||
}
|
||||
R_FREE (config_path);
|
||||
if (fail) {
|
||||
sdb_free (db);
|
||||
free (fncfg);
|
||||
return NULL;
|
||||
}
|
||||
fncfg->instance = sdb_get (db, "instance", NULL);
|
||||
fncfg->creds = r_str_newf ("%s:%s", sdb_const_get (db, "user", NULL),
|
||||
sdb_const_get (db, "password", NULL));
|
||||
sdb_free (db);
|
||||
if (!fncfg->instance || !fncfg->creds) {
|
||||
free (fncfg->instance);
|
||||
free (fncfg->creds);
|
||||
free (fncfg);
|
||||
return NULL;
|
||||
}
|
||||
return fncfg;
|
||||
}
|
||||
|
||||
static void cfg_free (FediNotifsCFG *cfg) {
|
||||
if (cfg) {
|
||||
free (cfg->instance);
|
||||
free (cfg->creds);
|
||||
free (cfg);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct fedi_notif_t {
|
||||
char *acct;
|
||||
char *display_name;
|
||||
char *type;
|
||||
} FediNotif;
|
||||
|
||||
typedef struct json_notif_parser_t {
|
||||
ut32 depth;
|
||||
RQueue *notif_queue;
|
||||
RStack *code_stack;
|
||||
FediNotif *cur;
|
||||
} JsonNParser;
|
||||
|
||||
typedef int (*HandleJson)(JsonNParser *jnp, int type, const char *data, ut32 len);
|
||||
|
||||
static int handle_account_acct (JsonNParser *jnp, int type, const char *data, ut32 len) {
|
||||
jnp->cur->acct = R_NEWS0 (char, len + 1);
|
||||
memcpy (jnp->cur->acct, data, len);
|
||||
r_stack_pop (jnp->code_stack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_account_display_name (JsonNParser *jnp, int type, const char *data, ut32 len) {
|
||||
jnp->cur->display_name = R_NEWS0 (char, len + 1);
|
||||
memcpy (jnp->cur->display_name, data, len);
|
||||
r_stack_pop (jnp->code_stack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_account (JsonNParser *jnp, int type, const char *data, ut32 len) {
|
||||
if (type == JSON_OBJECT_BEGIN) {
|
||||
jnp->depth++;
|
||||
return 0;
|
||||
}
|
||||
if (type == JSON_KEY && len == 4 && !memcmp (data, "acct", 4)) {
|
||||
r_stack_push (jnp->code_stack, handle_account_acct);
|
||||
return 0;
|
||||
}
|
||||
if (type == JSON_KEY && len == 12 && !memcmp (data, "display_name", 12)) {
|
||||
r_stack_push (jnp->code_stack, handle_account_display_name);
|
||||
return 0;
|
||||
}
|
||||
if (type == JSON_OBJECT_END) {
|
||||
if (2 == jnp->depth--) {
|
||||
r_stack_pop (jnp->code_stack);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_status (JsonNParser *jnp, int type, const char *data, ut32 len) {
|
||||
if (type == JSON_OBJECT_BEGIN) {
|
||||
jnp->depth++;
|
||||
return 0;
|
||||
}
|
||||
if (type == JSON_OBJECT_END) {
|
||||
if (2 == jnp->depth--) {
|
||||
r_stack_pop (jnp->code_stack);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_type (JsonNParser *jnp, int type, const char *data, ut32 len) {
|
||||
jnp->cur->type = R_NEWS0 (char, len + 1);
|
||||
memcpy (jnp->cur->type, data, len);
|
||||
r_stack_pop (jnp->code_stack);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parser_cb (void *user, int type, const char *data, uint32_t length) {
|
||||
JsonNParser *jnp = (JsonNParser *)user;
|
||||
HandleJson h = (HandleJson)r_stack_peek (jnp->code_stack);
|
||||
if (h) {
|
||||
return h(jnp, type, data, length);
|
||||
}
|
||||
if (type == JSON_OBJECT_BEGIN) {
|
||||
if (jnp->depth == 0) {
|
||||
jnp->cur = R_NEW0 (FediNotif);
|
||||
}
|
||||
jnp->depth++;
|
||||
}
|
||||
if (type == JSON_KEY) {
|
||||
if (length == 7 && !memcmp (data, "account", 7)) {
|
||||
r_stack_push (jnp->code_stack, handle_account);
|
||||
return 0;
|
||||
}
|
||||
if (length == 6 && !memcmp (data, "status", 6)) {
|
||||
r_stack_push (jnp->code_stack, handle_status);
|
||||
return 0;
|
||||
}
|
||||
if (length == 4 && !memcmp (data, "type", 4)) {
|
||||
r_stack_push (jnp->code_stack, handle_type);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (type == JSON_OBJECT_END) {
|
||||
if (jnp->depth == 1) {
|
||||
r_queue_enqueue (jnp->notif_queue, jnp->cur);
|
||||
jnp->cur = NULL;
|
||||
}
|
||||
jnp->depth--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t write_data(void *ptr, size_t size, size_t nmemb, void *user) {
|
||||
RIODesc *desc = (RIODesc *)user;
|
||||
size_t dlen = size * nmemb;
|
||||
while (dlen > 0x7fffffff) {
|
||||
r_io_desc_write (desc, (const ut8 *)ptr, 0x7fffffff);
|
||||
ptr += 0x7fffffff;
|
||||
dlen -= 0x7fffffff;
|
||||
}
|
||||
r_io_desc_write (desc, (const ut8 *)ptr, (int)dlen);
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
int main (int argc, char *argv[]) {
|
||||
FediNotifsCFG *cfg = get_cfg ();
|
||||
if (!cfg) {
|
||||
return -1;
|
||||
}
|
||||
char *notifs_url = r_str_newf ("%s/api/v1/notifications", cfg->instance);
|
||||
if (!notifs_url) {
|
||||
cfg_free (cfg);
|
||||
return -1;
|
||||
}
|
||||
RIO *io = r_io_new ();
|
||||
if (!io) {
|
||||
free (notifs_url);
|
||||
cfg_free (cfg);
|
||||
return -1;
|
||||
}
|
||||
int tree_fd = r_io_fd_open (io, "treebuf://", R_PERM_RW, 0);
|
||||
CURL *curl = curl_easy_init();
|
||||
if(!curl) {
|
||||
r_io_free (io);
|
||||
free (notifs_url);
|
||||
cfg_free (cfg);
|
||||
return -1;
|
||||
}
|
||||
curl_easy_setopt (curl, CURLOPT_HTTPGET, 1L);
|
||||
curl_easy_setopt (curl, CURLOPT_URL, notifs_url);
|
||||
curl_easy_setopt (curl, CURLOPT_HTTPAUTH, (long)CURLAUTH_BASIC);
|
||||
curl_easy_setopt (curl, CURLOPT_USERPWD, cfg->creds);
|
||||
curl_easy_setopt (curl, CURLOPT_WRITEFUNCTION, write_data);
|
||||
curl_easy_setopt (curl, CURLOPT_WRITEDATA, r_io_desc_get (io, tree_fd));
|
||||
curl_easy_perform (curl);
|
||||
ut64 rec_len = r_io_fd_seek (io, tree_fd, 0LL, R_IO_SEEK_CUR);
|
||||
curl_easy_cleanup (curl);
|
||||
free (notifs_url);
|
||||
cfg_free (cfg);
|
||||
char *data = malloc (rec_len + 1);
|
||||
r_io_fd_read_at (io, tree_fd, 0ULL, data, (int)rec_len);
|
||||
data[rec_len] = '\x00';
|
||||
r_io_free (io);
|
||||
JsonNParser jnp = {false, r_queue_new (2), r_stack_new (8)};
|
||||
json_parser parser;
|
||||
json_parser_init (&parser, NULL, parser_cb, &jnp);
|
||||
json_parser_string (&parser, data, rec_len, NULL);
|
||||
free (data);
|
||||
json_parser_free (&parser);
|
||||
r_stack_free (jnp.code_stack);
|
||||
while (!r_queue_is_empty (jnp.notif_queue)) {
|
||||
FediNotif *notif = (FediNotif *)r_queue_dequeue (jnp.notif_queue);
|
||||
printf ("%s: @%s\n%s\n", notif->display_name, notif->acct, notif->type);
|
||||
puts ("==========================================\n");
|
||||
free (notif->acct);
|
||||
free (notif->display_name);
|
||||
free (notif->type);
|
||||
free (notif);
|
||||
}
|
||||
r_queue_free (jnp.notif_queue);
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user