aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRatakor <ratakor@disroot.org>2023-06-12 00:29:14 +0200
committerRatakor <ratakor@disroot.org>2023-06-12 00:29:14 +0200
commit264964ec139987d544a31b39f5e112d0ea3072c3 (patch)
treea387f42394c412a85f15308bda8cc624100d62d1
parent8320fd90666db07b5a90f5c3749279c6bb205a5e (diff)
Lot of changes, read commit messagev0.0.8
Replace warn() and die() with WARN and DIE macros. Replace emsg() in raids.c with discord_send_message(). Add efopen() in util.c. Add all Scream of Terra member to slayers[] in raids.c. Add automatic ping for overcap_msg() instead of just message with name. Add stats_admin command. Fix stats command -> need to use cJSON lib. Fix info to not output kingdom when it's null. Fix typo in parse_line() in stats.c. Remove ecalloc().
-rw-r--r--Makefile3
-rw-r--r--README.md4
-rw-r--r--src/cmd_help.c13
-rw-r--r--src/cmd_info.c10
-rw-r--r--src/cmd_lbraid.c11
-rw-r--r--src/cmd_leaderboard.c8
-rw-r--r--src/cmd_source.c8
-rw-r--r--src/cmd_uraid.c9
-rw-r--r--src/init.c51
-rw-r--r--src/main.c4
-rw-r--r--src/nolan.h5
-rw-r--r--src/ocr.c33
-rw-r--r--src/raids.c156
-rw-r--r--src/stats.c180
-rw-r--r--src/util.c41
-rw-r--r--src/util.h30
16 files changed, 315 insertions, 251 deletions
diff --git a/Makefile b/Makefile
index 9b283a1..26ff26d 100644
--- a/Makefile
+++ b/Makefile
@@ -11,9 +11,10 @@ OBJS := ${SRCS:%=${BUILD_DIR}/%.o}
DISCORDLIBS = -ldiscord -lcurl -lpthread
TESSLIBS = -ltesseract -lleptonica
GDLIBS = -lgd -lpng -lz -ljpeg -lfreetype -lm
+CJSONLIB = -lcjson
INCS = -I/usr/local/include -I/usr/include
-LIBS = -L/usr/lib -L/usr/local/lib ${DISCORDLIBS} ${TESSLIBS} ${GDLIBS}
+LIBS = -L/usr/lib -L/usr/local/lib ${DISCORDLIBS} ${TESSLIBS} ${GDLIBS} ${CJSONLIB}
DEBUG_FLAGS = -O0 -g -W -Wall -Wmissing-prototypes
CFLAGS += -std=c99 -pedantic -D_DEFAULT_SOURCE ${INCS}
diff --git a/README.md b/README.md
index 47f1506..e609167 100644
--- a/README.md
+++ b/README.md
@@ -5,14 +5,16 @@ A discord bot for Orna.
- [concord](https://github.com/Cogmasters/concord)
- [tesseract](https://github.com/tesseract-ocr/tesseract)
- [gd](https://github.com/libgd/libgd)
+- [cJSON](https://github.com/DaveGamble/cJSON)
## TODO
### features
-- add option to correct stats ?
+- add cmd_correct to correct stats
- ascensions (track mats)
### chore
+- change players' stats to unsigned long
- add documentation
- rework DIFF in ocr.c
- rework roles
diff --git a/src/cmd_help.c b/src/cmd_help.c
index f452b88..766cf08 100644
--- a/src/cmd_help.c
+++ b/src/cmd_help.c
@@ -24,20 +24,16 @@ help(char *buf, size_t siz)
strlcpy(buf, "Post a screenshot of your stats to ", siz);
for (i = 0; i < len; i++) {
p = strchr(buf, '\0');;
- rsiz = snprintf(p, siz, "<#%lu> ", stats_ids[i]);
- if (rsiz >= siz) {
- warn("nolan: truncation happened while writing help, \
-probably way too much channels for stats\n");
- }
+ snprintf(p, siz, "<#%lu> ", stats_ids[i]);
if (i < len - 1)
strlcat(buf, "or ", siz);
}
- strlcat(buf, "to enter the database.\n", siz);
+ strlcat(buf, "so I can have a look at your stats πŸ‘€\n", siz);
strlcat(buf, "Commands:\n", siz);
strlcat(buf, "\t/stats *screenshot*\n", siz);
strlcat(buf, "\t/info *[[@]user]*\n", siz);
strlcat(buf, "\t/leaderboard *category*\n", siz);
- /* catstr(buf, "\t/correct [category] [corrected value]\n", siz); */
+ /* strlcat(buf, "\t/correct *category* *corrected value*\n", siz); */
strlcat(buf, "\t/source *[kingdom]*\n", siz);
strlcat(buf, "\t/uraid *username* (only for Scream of Terra)\n", siz);
strlcat(buf, "\t/lbraid (only for Scream of Terra)\n", siz);
@@ -47,7 +43,8 @@ probably way too much channels for stats\n");
strlcat(buf, PREFIX, siz);
rsiz = strlcat(buf, " instead of /.", siz);
if (rsiz >= siz)
- warn("nolan: truncation happened while writing help\n");
+ WARN("string truncation\n\
+\033[33mhint:\033[39m this is probably because stats_ids is too big");
}
void
diff --git a/src/cmd_info.c b/src/cmd_info.c
index 787a9d1..b038f28 100644
--- a/src/cmd_info.c
+++ b/src/cmd_info.c
@@ -98,9 +98,13 @@ write_info(char *buf, size_t siz, const Player *player)
/* -2 to not include upadte and userid */
for (i = 0; i < LENGTH(fields) - 2; i++) {
- if (i <= 1) { /* name and kingdom */
- snprintf(p, siz, "%s: %s\n", fields[i],
- ((char **)player)[i]);
+ if (i == 0) { /* name */
+ snprintf(p, siz, "%s: %s\n", fields[i], player->name);
+ } else if (i == 1) { /* kingdom */
+ if (strcmp(player->kingdom, "(null)") != 0) {
+ snprintf(p, siz, "%s: %s\n", fields[i],
+ player->kingdom);
+ }
} else if (i == 7) { /* playtime */
plt = playtime_to_str(((long *)player)[i]);
snprintf(p, siz, "%s: %s\n", fields[i], plt);
diff --git a/src/cmd_lbraid.c b/src/cmd_lbraid.c
index ba2cd38..d68a9e3 100644
--- a/src/cmd_lbraid.c
+++ b/src/cmd_lbraid.c
@@ -30,9 +30,7 @@ parse_file(char *fname, Slayer slayers[], size_t *nslayers)
unsigned int i;
unsigned long dmg;
- if ((fp = fopen(fname, "r")) == NULL)
- return;
-
+ fp = efopen(fname, "r");
while (fgets(line, LINE_SIZE, fp)) {
endname = strchr(line, DELIM);
dmg = strtoul(endname + 1, NULL, 10);
@@ -64,9 +62,8 @@ load_files(Slayer slayers[], size_t *nslayers)
for (i = 0; i < 6; i++) {
snprintf(fname, sizeof(fname), "%s%ld.csv",
RAIDS_FOLDER, day - i);
- if (file_exists(fname)) {
+ if (file_exists(fname))
parse_file(fname, slayers, nslayers);
- }
}
}
@@ -94,10 +91,10 @@ write_lbraid(char *buf, int siz, Slayer slayers[], size_t nslayers)
for (i = 0; i < lb_max; i++) {
siz -= snprintf(p, siz, "%d. %s: %'lu damage\n", i,
slayers[i].name, slayers[i].damage);
- if (siz <= 0)
- warn("nolan: string truncation in %s\n", __func__);
p = strchr(buf, '\0');
}
+ if (siz <= 0)
+ WARN("string truncation");
}
void
diff --git a/src/cmd_leaderboard.c b/src/cmd_leaderboard.c
index 11a09bc..e40fdaa 100644
--- a/src/cmd_leaderboard.c
+++ b/src/cmd_leaderboard.c
@@ -195,8 +195,8 @@ write_leaderboard(char *buf, size_t siz, u64snowflake userid)
}
rsiz = strlcat(buf, player, siz);
if (rsiz >= siz) {
- warn("nolan: string truncation happened while writing \
-leaderboard.\nThis is probably because LB_MAX is too big.\n");
+ WARN("string truncation\n\
+\033[33mhint:\033[39m this is probably because LB_MAX is too big");
}
}
@@ -209,8 +209,8 @@ leaderboard.\nThis is probably because LB_MAX is too big.\n");
write_player(player, psiz, i, 1);
rsiz = strlcat(buf, player, siz);
if (rsiz >= siz) {
- warn("nolan: string truncation happened while writing \
-leaderboard.\nThis is probably because LB_MAX is too big.\n");
+ WARN("string truncation\n\
+\033[33mhint:\033[39m this is probably because LB_MAX is too big");
}
}
}
diff --git a/src/cmd_source.c b/src/cmd_source.c
index d17d288..6e9d2c9 100644
--- a/src/cmd_source.c
+++ b/src/cmd_source.c
@@ -35,9 +35,7 @@ load_source(size_t *fszp)
char *res, line[LINE_SIZE], *end;
size_t mfsz = LINE_SIZE + nplayers * LINE_SIZE;
- if ((fp = fopen(STATS_FILE, "r")) == NULL)
- die("nolan: Failed to open %s (read)\n", STATS_FILE);
-
+ fp = efopen(STATS_FILE, "r");
res = emalloc(mfsz);
*res = '\0';
while (fgets(line, LINE_SIZE, fp) != NULL) {
@@ -61,9 +59,7 @@ load_sorted_source(size_t *fszp, char *kingdom)
char *res, line[LINE_SIZE], *kd, *endkd, *end;
size_t mfsz = LINE_SIZE + nplayers * LINE_SIZE;
- if ((fp = fopen(STATS_FILE, "r")) == NULL)
- die("nolan: Failed to open %s (read)\n", STATS_FILE);
-
+ fp = efopen(STATS_FILE, "r");
res = emalloc(mfsz);
fgets(line, LINE_SIZE, fp); /* fields name */
/* skip everything after codex */
diff --git a/src/cmd_uraid.c b/src/cmd_uraid.c
index 23c3b52..788af07 100644
--- a/src/cmd_uraid.c
+++ b/src/cmd_uraid.c
@@ -49,9 +49,7 @@ parse_file(char *fname, char *username)
unsigned long dmg;
char line[LINE_SIZE], *endname;
- if ((fp = fopen(fname, "r")) == NULL)
- return 0;
-
+ fp = efopen(fname, "r");
while (fgets(line, LINE_SIZE, fp)) {
endname = strchr(line, DELIM);
dmg = strtoul(endname + 1, NULL, 10);
@@ -77,9 +75,8 @@ load_files(char *username, unsigned long *dmgs)
for (i = 0; i < 6; i++) {
snprintf(fname, sizeof(fname), "%s%ld.csv",
RAIDS_FOLDER, day - i);
- if (file_exists(fname)) {
+ if (file_exists(fname))
dmgs[i] = parse_file(fname, username);
- }
}
return dmgs;
@@ -114,7 +111,7 @@ write_uraid(char *buf, int siz, char *username, unsigned long *dmgs)
}
siz -= snprintf(p, siz, "\nTotal: %'lu damage\n", total);
if (siz <= 0)
- warn("nolan: string truncation in %s\n", __func__);
+ WARN("string truncation");
}
void
diff --git a/src/init.c b/src/init.c
index 3096d46..d433632 100644
--- a/src/init.c
+++ b/src/init.c
@@ -10,17 +10,18 @@ static Player load_player(unsigned int line);
void
create_folders(void)
{
- if (!file_exists(SAVE_FOLDER)) {
- if (mkdir(SAVE_FOLDER, 0755) == -1)
- die("nolan: Failed to create %s\n", SAVE_FOLDER);
- }
- if (!file_exists(IMAGES_FOLDER)) {
- if (mkdir(IMAGES_FOLDER, 0755) == -1)
- die("nolan: Failed to create %s\n", IMAGES_FOLDER);
- }
- if (!file_exists(RAIDS_FOLDER)) {
- if (mkdir(RAIDS_FOLDER, 0755) == -1)
- die("nolan: Failed to create %s\n", RAIDS_FOLDER);
+ unsigned int i;
+ const char *folders[] = {
+ SAVE_FOLDER,
+ IMAGES_FOLDER,
+ RAIDS_FOLDER,
+ };
+
+ for (i = 0; i < LENGTH(folders); i++) {
+ if (file_exists(folders[i]))
+ continue;
+ if (mkdir(folders[i], 0755) == -1)
+ DIE("failed to create %s\n", folders[i]);
}
}
@@ -38,7 +39,9 @@ create_stats_file(void)
size = ftell(fp);
}
- if (size == 0 && (fp = fopen(STATS_FILE, "w")) != NULL) {
+ if (size == 0) {
+ if (fp) fclose(fp);
+ fp = efopen(STATS_FILE, "w");
for (i = 0; i < LENGTH(fields) - 1; i++)
fprintf(fp, "%s%c", fields[i], DELIM);
fprintf(fp, "%s\n", fields[LENGTH(fields) - 1]);
@@ -51,8 +54,8 @@ create_slash_commands(struct discord *client)
{
#ifndef DEVEL
create_slash_help(client);
- /* create_slash_stats(client); */
- /* create_slash_stats_admin(client); */
+ create_slash_stats(client);
+ create_slash_stats_admin(client);
create_slash_info(client);
create_slash_leaderboard(client);
create_slash_source(client);
@@ -70,14 +73,13 @@ load_player(unsigned int line)
unsigned int i = 0;
if (line <= 1)
- die("nolan: Tried to load the description line as a player\n");
- if ((fp = fopen(STATS_FILE, "r")) == NULL)
- die("nolan: Failed to open %s (read)\n", STATS_FILE);
+ DIE("tried to load the description line as a player");
+ fp = efopen(STATS_FILE, "r");
while (i++ < line && (p = fgets(buf, LINE_SIZE, fp)) != NULL);
fclose(fp);
if (p == NULL)
- die("nolan: Line %d is not present in %s\n", line, STATS_FILE);
+ DIE("line %d is not present in %s", line, STATS_FILE);
i = 0;
delim = p;
@@ -97,8 +99,10 @@ load_player(unsigned int line)
p = delim + 1;
i++;
}
- if (i != LENGTH(fields) - 1)
- die("nolan: Player on line %d is missing a field\n", line);
+ if (i != LENGTH(fields) - 1) {
+ DIE("player in %s on line %d is missing a field", STATS_FILE,
+ line);
+ }
player.userid = strtoul(p, NULL, 10);
return player;
@@ -111,16 +115,13 @@ init_players(void)
char buf[LINE_SIZE];
unsigned int i;
- if ((fp = fopen(STATS_FILE, "r")) == NULL)
- die("nolan: Failed to open %s (read)\n", STATS_FILE);
-
+ fp = efopen(STATS_FILE, "r");
while (fgets(buf, LINE_SIZE, fp))
nplayers++;
nplayers--; /* first line is not a player */
if (nplayers > MAX_PLAYERS)
- die("nolan: There is too much players to load (max:%d)\n",
- MAX_PLAYERS);
+ DIE("there is too much players to load (max:%lu)", MAX_PLAYERS);
for (i = 0; i < nplayers; i++)
players[i] = load_player(i + 2);
diff --git a/src/main.c b/src/main.c
index 2aa6060..5ad8c79 100644
--- a/src/main.c
+++ b/src/main.c
@@ -34,7 +34,7 @@ const char *fields[] = {
};
int
-main(void)
+main(int argc, char *argv[])
{
char *src[] = { "src", "source" };
char *lb[] = { "lb", "leaderboard" };
@@ -42,7 +42,7 @@ main(void)
#ifndef DEVEL
if (getuid() != 0)
- die("Please run nolan as root\n");
+ DIE("please run %s as root", argv[0]);
#endif /* DEVEL */
setlocale(LC_NUMERIC, "");
diff --git a/src/nolan.h b/src/nolan.h
index 66d8e22..9bff5b2 100644
--- a/src/nolan.h
+++ b/src/nolan.h
@@ -12,14 +12,17 @@
#define MAX_MESSAGE_LEN 2000 + 1
#define MAX_USERNAME_LEN 32 + 1
#define MAX_KINGDOM_LEN 32 + 1
+
#ifdef DEVEL
#define SAVE_FOLDER "./"
#else
#define SAVE_FOLDER "/var/lib/nolan/"
#endif /* DEVEL */
+
#define IMAGES_FOLDER SAVE_FOLDER "images/"
#define RAIDS_FOLDER SAVE_FOLDER "raids/"
#define STATS_FILE SAVE_FOLDER FILENAME
+
#define ROLE_GUILD_ID 999691133103919135 /* this is only for to Orna FR */
/* ALL FIELDS MUST HAVE THE SAME SIZE */
@@ -72,7 +75,7 @@ void on_ready(struct discord *client, const struct discord_ready *event);
void on_message(struct discord *client, const struct discord_message *event);
/* ocr.c */
-void curl(char *url, char *fname);
+unsigned int curl(char *url, char *fname);
int crop(char *fname, int type);
char *ocr(char *fname, char *lang);
diff --git a/src/ocr.c b/src/ocr.c
index f9e23bb..c9515f7 100644
--- a/src/ocr.c
+++ b/src/ocr.c
@@ -20,10 +20,11 @@ write_data(void *ptr, size_t size, size_t nmemb, void *stream)
return written;
}
-void
+unsigned int
curl(char *url, char *fname)
{
CURL *handle;
+ CURLcode ret;
FILE *fp;
curl_global_init(CURL_GLOBAL_ALL);
@@ -33,15 +34,15 @@ curl(char *url, char *fname)
curl_easy_setopt(handle, CURLOPT_URL, url);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
- if ((fp = fopen(fname, "wb")) == NULL)
- die("nolan: Failed to open %s\n", fname);
-
+ fp = efopen(fname, "wb");
curl_easy_setopt(handle, CURLOPT_WRITEDATA, fp);
- curl_easy_perform(handle);
+ ret = curl_easy_perform(handle);
fclose(fp);
curl_easy_cleanup(handle);
curl_global_cleanup();
+
+ return ret;
}
int
@@ -72,31 +73,25 @@ crop(char *fname, int type)
gdImage *im, *cropped;
gdRect rect;
- if ((fp = fopen(fname, "rb")) == NULL)
- die("nolan: Failed to open %s\n", fname);
-
+ fp = efopen(fname, "rb");
if (type == 0)
im = gdImageCreateFromJpeg(fp);
else
im = gdImageCreateFromPng(fp);
fclose(fp);
+
if (im == NULL)
return 1;
-
if (write_rect(&rect, im) == 1)
return 1;
cropped = gdImageCrop(im, &rect);
-
- if ((fp = fopen(fname, "wb")) == NULL)
- die("nolan: Failed to open %s\n", fname);
-
+ fp = efopen(fname, "wb");
if (type == 0)
gdImageJpeg(cropped, fp, 100);
else
gdImagePng(cropped, fp);
fclose(fp);
-
gdImageDestroy(cropped);
gdImageDestroy(im);
@@ -110,16 +105,18 @@ ocr(char *fname, char *lang)
PIX *img;
char *txt_ocr, *txt_out;
- if ((img = pixRead(fname)) == NULL)
- die("nolan: Error reading image\n");
+ if ((img = pixRead(fname)) == NULL) {
+ WARN("failed to read image (%s)", fname);
+ return NULL;
+ }
handle = TessBaseAPICreate();
if (TessBaseAPIInit3(handle, NULL, lang) != 0)
- die("nolan: Error initialising tesseract\n");
+ DIE("failed to init tesseract (lang:%s)", lang);
TessBaseAPISetImage2(handle, img);
if (TessBaseAPIRecognize(handle, NULL) != 0)
- die("nolan: Error in tesseract recognition\n");
+ DIE("failed tesseract recognition");
txt_ocr = TessBaseAPIGetUTF8Text(handle);
txt_out = strdup(txt_ocr);
diff --git a/src/raids.c b/src/raids.c
index 64f45f2..80fa593 100644
--- a/src/raids.c
+++ b/src/raids.c
@@ -1,3 +1,4 @@
+#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
@@ -6,7 +7,14 @@
#define DAMAGE_CAP 300000000 / 7 /* daily */
-static void emsg(struct discord *client, const struct discord_message *event);
+struct Slayers {
+ char *name;
+ u64snowflake userid;
+};
+
+static void discord_send_message(struct discord *client,
+ const u64snowflake channel_id,
+ const char *fmt, ...);
static char *skip_to_slayers(char *txt);
static char *trim_name(char *name);
static unsigned long trim_dmg(char *str);
@@ -16,10 +24,10 @@ static unsigned long adjust(unsigned long dmg, char *raid);
static void save_to_new_file(Slayer slayers[], size_t nslayers, char *fname,
char *raid);
static void overcap_msg(char *name, unsigned long dmg, struct discord *client,
- const struct discord_message *event);
+ const u64snowflake channel_id);
static void save_to_file(Slayer slayers[], size_t nslayers, char *raid,
struct discord *client,
- const struct discord_message *event);
+ const u64snowflake channel_id);
static const char *delims[] = {
"+ Raid options",
@@ -38,19 +46,70 @@ static const char *garbageslayer[] = {
"討 伐 θ€…"
};
+const struct Slayers slayers[] = {
+ { "Davethegray", 618842282564648976 },
+ { "SmittyWerbenJaeger", 372349296772907008 },
+ { "Damaquandey", 237305375211257866 },
+ { "Fhullegans", 401213200688742412 },
+ { "PhilipXIVTheGintonicKnight", 653570978068299777 },
+ { "Heatnick", 352065341901504512 },
+ { "Tazziekat", 669809258153639937 },
+ { "Basic", 274260433521737729 },
+ { "KovikFrunobulax", 589110637267779584 },
+ { "GoDLiKeKiLL", 425706840060592130 },
+ { "Shazaaamm", 516711375330869367 },
+ { "Yiri", 179396886254452736 },
+ { "MilesandroIlgnorante", 163351655478329344 },
+ { "HurricaneHam", 245010787817488384 },
+ { "SneakPeek", 559664517198381057 },
+ { "Ensseric", 659545497144655903 },
+ { "Mijikai", 163048434478088192 },
+ { "BigYoshi", 247796779804917770 },
+ { "Ratakor", 277534384175841280 },
+ { "oxDje", 452860420034789396 },
+ { "LordDroopy", 704457235467730986 },
+ { "discosoutmurdersin", 609770024944664657 },
+ { "EchinChanfromHELL", 819244261760565280 },
+ { "ANIMAL", 222464347568472064 },
+ { "Soreloser", 345516161838088192 },
+ { "KyzeMythos", 189463147571052544 },
+ { "ElucidatorS", 636975696186441739 },
+ { "BrewmasterAalst", 155893692740141056 },
+ { "Tiroc", 519282218057596929 },
+ { "Kyzee", 685267547377106990 },
+ { "Shadowssin", 265837021400924162 },
+ { "Burtonlol", 353969780702576641 },
+ { "Wingeren", 75695406381543424 },
+ { "Schmiss", 460552631778279457 },
+ { "Bloodshade", 329400042324623371 },
+ { "Randylittle", 555760640329777153 },
+ { "Sunveela", 269171964105457665 },
+ { "SaiSenpai", 958922552284172349 },
+ { "Jakealope", 164209517926678528 },
+ { "CleverCaitlin", 297650487585406976 },
+ { "Demmo", 807849505105248287 }, /* Demm974 */
+};
+
+/* this should be in util.c but it's only used here*/
void
-emsg(struct discord *client, const struct discord_message *event)
+discord_send_message(struct discord *client, const u64snowflake channel_id,
+ const char *fmt, ...)
{
char buf[MAX_MESSAGE_LEN];
+ size_t rsiz;
+ va_list ap;
+
+ va_start(ap, fmt);
+ rsiz = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+
+ if (rsiz >= sizeof(buf))
+ WARN("string truncation");
- warn("nolan: Failed to read raid image\n");
- snprintf(buf, sizeof(buf),
- "Error: Failed to read image <@%lu>.\nFix me <@%lu>",
- event->author->id, ADMIN);
struct discord_create_message msg = {
.content = buf
};
- discord_create_message(client, event->channel_id, &msg, NULL);
+ discord_create_message(client, channel_id, &msg, NULL);
}
char *
@@ -89,7 +148,7 @@ skip_to_slayers(char *txt)
return NULL;
}
-/* trim everything that is not a letter or a space */
+/* trim everything that is not a letter ~~or a space~~ */
char *
trim_name(char *name)
{
@@ -101,7 +160,7 @@ trim_name(char *name)
r = name;
w = name;
do {
- if (*r == ' ' || (*r >= 'A' && *r <= 'Z') || (*r >= 'a' && *r <= 'z'))
+ if ((*r >= 'A' && *r <= 'Z') || (*r >= 'a' && *r <= 'z'))
*w++ = *r;
} while (*r++);
*w = '\0';
@@ -223,8 +282,8 @@ save_to_new_file(Slayer slayers[], size_t nslayers, char *fname, char *raid)
{
FILE *fp;
unsigned int i;
- if ((fp = fopen(fname, "w")) == NULL)
- die("nolan: Failed to open %s\n", fname);
+
+ fp = efopen(fname, "w");
for (i = 0; i < nslayers; i++) {
fprintf(fp, "%s%c%lu\n", slayers[i].name, DELIM,
adjust(slayers[i].damage, raid));
@@ -233,28 +292,35 @@ save_to_new_file(Slayer slayers[], size_t nslayers, char *fname, char *raid)
fclose(fp);
}
+/* TODO: use a weekly cap instead */
void
overcap_msg(char *name, unsigned long dmg, struct discord *client,
- const struct discord_message *event)
+ const u64snowflake channel_id)
{
- char buf[MAX_MESSAGE_LEN];
+ unsigned int i = 0;
+ size_t len;
if (dmg < DAMAGE_CAP)
return;
- /* TODO: match name with userid + use a weekly cap instead */
- snprintf(buf, sizeof(buf), "%s has overcapped the limit by %'lu \
-damage he is now at %'lu damage.", name, dmg - DAMAGE_CAP, dmg);
-
- struct discord_create_message msg = {
- .content = buf
- };
- discord_create_message(client, event->channel_id, &msg, NULL);
+ len = strlen(name) - 3;
+ while (i < LENGTH(slayers) && strncasecmp(name, slayers[i].name, len) != 0)
+ i++;
+
+ if (i == MAX_SLAYERS) {
+ discord_send_message(client, channel_id,
+ "%s has overcapped the limit by %'lu \
+damage, he is now at %'lu damage.", name, dmg - DAMAGE_CAP, dmg);
+ } else {
+ discord_send_message(client, channel_id,
+ "<@%lu> has overcapped the limit by %'lu \
+damage, he is now at %'lu damage.", slayers[i].userid, dmg - DAMAGE_CAP, dmg);
+ }
}
void
save_to_file(Slayer slayers[], size_t nslayers, char *raid,
- struct discord *client, const struct discord_message *event)
+ struct discord *client, const u64snowflake channel_id)
{
FILE *w, *r;
char line[LINE_SIZE], *endname, fname[128], tmpfname[128];
@@ -262,7 +328,6 @@ save_to_file(Slayer slayers[], size_t nslayers, char *raid,
unsigned long olddmg, newdmg;
long day = time(NULL) / 86400;
- /* assert with rsiz >= siz ? */
snprintf(fname, sizeof(fname), "%s%ld.csv", RAIDS_FOLDER, day);
strlcpy(tmpfname, SAVE_FOLDER, sizeof(tmpfname));
strlcat(tmpfname, "tmpfile2", sizeof(tmpfname));
@@ -270,8 +335,7 @@ save_to_file(Slayer slayers[], size_t nslayers, char *raid,
save_to_new_file(slayers, nslayers, fname, raid);
return;
}
- if ((w = fopen(tmpfname, "w")) == NULL)
- die("nolan: Failed to open %s\n", tmpfname);
+ w = efopen(tmpfname, "w");
while (fgets(line, LINE_SIZE, r)) {
endname = strchr(line, DELIM);
@@ -280,7 +344,7 @@ save_to_file(Slayer slayers[], size_t nslayers, char *raid,
for (i = 0; i < nslayers; i++) {
if (!slayers[i].found_in_file) {
/* should be strcmp but for common mistakes */
- if (strncmp(slayers[i].name, line,
+ if (strncasecmp(slayers[i].name, line,
strlen(slayers[i].name) - 3) == 0) {
slayers[i].found_in_file = 1;
break;
@@ -290,7 +354,7 @@ save_to_file(Slayer slayers[], size_t nslayers, char *raid,
if (i < nslayers) {
olddmg = strtoul(endname + 1, NULL, 10);
newdmg = olddmg + adjust(slayers[i].damage, raid);
- overcap_msg(slayers[i].name, newdmg, client, event);
+ overcap_msg(slayers[i].name, newdmg, client, channel_id);
fprintf(w, "%s%c%lu\n", slayers[i].name, DELIM, newdmg);
} else {
if (endname)
@@ -315,7 +379,8 @@ save_to_file(Slayer slayers[], size_t nslayers, char *raid,
void
on_raids(struct discord *client, const struct discord_message *event)
{
- unsigned int i;
+ int is_png;
+ unsigned int i, ret;
char *txt = NULL, fname[128];
size_t nslayers;
Slayer slayers[MAX_SLAYERS];
@@ -325,15 +390,19 @@ on_raids(struct discord *client, const struct discord_message *event)
.sync = &chan,
};
- if (strcmp(event->attachments->array->content_type, "image/png") == 0) {
+ is_png = (strcmp(event->attachments->array->content_type,
+ "image/png") == 0) ? 1 : 0;
+ if (is_png)
snprintf(fname, sizeof(fname), "%s/raids.png", IMAGES_FOLDER);
- curl(event->attachments->array->url, fname);
- crop(fname, 1);
- } else { /* always a jpg, check on_message() */
+ else
snprintf(fname, sizeof(fname), "%s/raids.jpg", IMAGES_FOLDER);
- curl(event->attachments->array->url, fname);
- crop(fname, 0);
+ if ((ret = curl(event->attachments->array->url, fname)) != 0) {
+ WARN("curl failed CURLcode:%u", ret);
+ discord_send_message(client, event->channel_id, "Error: \
+Failed to download image <@%lu>.\nFix me <@%lu>", event->author->id, ADMIN);
+ return;
}
+ crop(fname, is_png);
for (i = 0; i < LENGTH(cn_slayer_ids); i++) {
if (event->author->id == cn_slayer_ids[i]) {
@@ -352,13 +421,22 @@ on_raids(struct discord *client, const struct discord_message *event)
if (txt == NULL)
txt = ocr(fname, "eng");
- if (txt == NULL || (nslayers = parse(slayers, txt)) == 0) {
- emsg(client, event);
+ if (txt == NULL) {
+ WARN("failed to read image");
+ discord_send_message(client, event->channel_id, "Error: \
+Failed to read image <@%lu>.\nFix me <@%lu>", event->author->id, ADMIN);
+ return;
+ }
+
+ nslayers = parse(slayers, txt);
+ if (nslayers == 0) {
+ discord_send_message(client, event->channel_id, "This is not \
+a correct screenshot sir <@%lu>.", event->author->id);
free(txt);
return;
}
free(txt);
discord_get_channel(client, event->channel_id, &rchan);
- save_to_file(slayers, nslayers, chan.name, client, event);
+ save_to_file(slayers, nslayers, chan.name, client, event->channel_id);
/* ^ will free slayers[].name */
}
diff --git a/src/stats.c b/src/stats.c
index 83b33a6..31038ab 100644
--- a/src/stats.c
+++ b/src/stats.c
@@ -1,11 +1,10 @@
-#include <ctype.h>
#include <stdlib.h>
#include <string.h>
-#include <time.h>
+#include <cjson/cJSON.h>
#include "nolan.h"
-#define LEN(X) (sizeof X - 1)
+#define STRLEN(STR) (sizeof STR - 1)
static long playtime_to_long(char *playtime, char *str);
static long trim_stat(char *str);
@@ -93,7 +92,7 @@ playtime_to_str(long playtime)
{
long days = playtime / 24;
long hours = playtime % 24;
- size_t siz = 32;
+ size_t siz = 36;
char *buf = emalloc(siz);
switch (hours) {
@@ -145,96 +144,99 @@ void
parse_line(Player *player, char *line)
{
char *str;
+ long stat;
- if (strncmp(line, "KINGDOM", LEN("KINGDOM")) == 0) {
+ if (strncmp(line, "KINGDOM", STRLEN("KINGDOM")) == 0) {
str = "KINGDOM ";
while (*str && (*line++ == *str++));
player->kingdom = line;
return;
}
- if (strncmp(line, "ROYAUME", LEN("ROYAUME")) == 0) {
+ if (strncmp(line, "ROYAUME", STRLEN("ROYAUME")) == 0) {
str = "ROYAUME ";
while (*str && (*line++ == *str++));
player->kingdom = line;
return;
}
- if (strncmp(line, "\\ele]]", LEN("\\ele]]")) == 0) { /* tess madness */
+ /* tesseract madness */
+ if (strncmp(line, "\\ele]]", STRLEN("\\ele]]")) == 0) {
str = "\\ele]] ";
while (*str && (*line++ == *str++));
player->kingdom = line;
return;
}
- if (strncmp(line, "PLAYTIME", LEN("PLAYTIME")) == 0) {
+ if (strncmp(line, "PLAYTIME", STRLEN("PLAYTIME")) == 0) {
str = "PLAYTIME ";
while (*str && (*line++ == *str++));
player->playtime = playtime_to_long(line, "days, ");
return;
}
- if (strncmp(line, "TEMPS DE JEU", LEN("TEMPS DE JEU")) == 0) {
+ if (strncmp(line, "TEMPS DE JEU", STRLEN("TEMPS DE JEU")) == 0) {
str = "TEMPS DE JEU ";
while (*str && (*line++ == *str++));
player->playtime = playtime_to_long(line, "jours, ");
return;
}
- if (strncmp(line, "ASCENSION LEVEL", LEN("ASCENSION LEVEL")) == 0 ||
- strncmp(line, "NIVEAU D'ELEVATION", LEN("NIVEAU D'ELEVATION")) == 0) {
+ if (strncmp(line, "ASCENSION LEVEL", STRLEN("ASCENSION LEVEL")) == 0 ||
+ strncmp(line, "NIVEAU D'ELEVATION", STRLEN("NIVEAU D'ELEVATION")) == 0) {
player->ascension = trim_stat(line);
- } else if (strncmp(line, "LEVEL", LEN("LEVEL")) == 0 ||
- strncmp(line, "NIVEAU", LEN("NIVEAU")) == 0) {
- player->level = trim_stat(line);
- } else if (strncmp(line, "GLOBAL RANK", LEN("GLOBAL RANK")) == 0 ||
- strncmp(line, "RANG GLOBAL", LEN("RANG GLOBAL")) == 0) {
+ } else if (strncmp(line, "LEVEL", STRLEN("LEVEL")) == 0 ||
+ strncmp(line, "NIVEAU", STRLEN("NIVEAU")) == 0) {
+ if ((stat = trim_stat(line)) <= 250)
+ player->level = stat;
+ } else if (strncmp(line, "GLOBAL RANK", STRLEN("GLOBAL RANK")) == 0 ||
+ strncmp(line, "RANG GLOBAL", STRLEN("RANG GLOBAL")) == 0) {
player->global = trim_stat(line);
- } else if (strncmp(line, "REGIONAL RANK", LEN("REGIONAL RANK")) == 0 ||
- strncmp(line, "RANG REGIONAL", LEN("RANG REGIONAL")) == 0) {
+ } else if (strncmp(line, "REGIONAL RANK", STRLEN("REGIONAL RANK")) == 0 ||
+ strncmp(line, "RANG REGIONAL", STRLEN("RANG REGIONAL")) == 0) {
player->regional = trim_stat(line);
- } else if (strncmp(line, "COMPETITIVE RANK", LEN("COMPETITIVE RANK")) == 0 ||
- strncmp(line, "RANG COMPETITIF", LEN("RANG COMPETITIF")) == 0) {
+ } else if (strncmp(line, "COMPETITIVE RANK", STRLEN("COMPETITIVE RANK")) == 0 ||
+ strncmp(line, "RANG COMPETITIF", STRLEN("RANG COMPETITIF")) == 0) {
player->competitive = trim_stat(line);
- } else if (strncmp(line, "MONSTERS SLAIN", LEN("MONSTERS SLAIN")) == 0 ||
- strncmp(line, "MONSTRES TUES", LEN("MONSTRES TUES")) == 0) {
+ } else if (strncmp(line, "MONSTERS SLAIN", STRLEN("MONSTERS SLAIN")) == 0 ||
+ strncmp(line, "MONSTRES TUES", STRLEN("MONSTRES TUES")) == 0) {
player->monsters = trim_stat(line);
- } else if (strncmp(line, "BOSSES SLAIN", LEN("BOSSES SLAIN")) == 0 ||
- strncmp(line, "BOSS TUES", LEN("BOSS TUES")) == 0) {
+ } else if (strncmp(line, "BOSSES SLAIN", STRLEN("BOSSES SLAIN")) == 0 ||
+ strncmp(line, "BOSS TUES", STRLEN("BOSS TUES")) == 0) {
player->bosses = trim_stat(line);
- } else if (strncmp(line, "PLAYERS DEFEATED", LEN("PLAYERS DEFEATED")) == 0 ||
- strncmp(line, "JOUEURS VAINCUS", LEN("JOUEURS VAINCUS")) == 0) {
+ } else if (strncmp(line, "PLAYERS DEFEATED", STRLEN("PLAYERS DEFEATED")) == 0 ||
+ strncmp(line, "JOUEURS VAINCUS", STRLEN("JOUEURS VAINCUS")) == 0) {
player->players = trim_stat(line);
- } else if (strncmp(line, "QUESTS COMPLETED", LEN("QUESTS COMPLETED")) == 0 ||
- strncmp(line, "QUETES TERMINEES", LEN("QUETES TERMINEES")) == 0) {
+ } else if (strncmp(line, "QUESTS COMPLETED", STRLEN("QUESTS COMPLETED")) == 0 ||
+ strncmp(line, "QUETES TERMINEES", STRLEN("QUETES TERMINEES")) == 0) {
player->quests = trim_stat(line);
- } else if (strncmp(line, "AREAS EXPLORED", LEN("AREAS EXPLORED")) == 0 ||
- strncmp(line, "TERRES EXPLOREES", LEN("TERRES EXPLOREES")) == 0) {
+ } else if (strncmp(line, "AREAS EXPLORED", STRLEN("AREAS EXPLORED")) == 0 ||
+ strncmp(line, "TERRES EXPLOREES", STRLEN("TERRES EXPLOREES")) == 0) {
player->explored = trim_stat(line);
- } else if (strncmp(line, "AREAS TAKEN", LEN("AREAS TAKEN")) == 0 ||
- strncmp(line, "TERRES PRISES", LEN("TERRES PRISES")) == 0) {
+ } else if (strncmp(line, "AREAS TAKEN", STRLEN("AREAS TAKEN")) == 0 ||
+ strncmp(line, "TERRES PRISES", STRLEN("TERRES PRISES")) == 0) {
player->taken = trim_stat(line);
- } else if (strncmp(line, "DUNGEONS CLEARED", LEN("DUNGEONS CLEARED")) == 0 ||
- strncmp(line, "DONJONS TERMINES", LEN("DONJONS TERMINES")) == 0) {
+ } else if (strncmp(line, "DUNGEONS CLEARED", STRLEN("DUNGEONS CLEARED")) == 0 ||
+ strncmp(line, "DONJONS TERMINES", STRLEN("DONJONS TERMINES")) == 0) {
player->dungeons = trim_stat(line);
- } else if (strncmp(line, "COLISEUM WINS", LEN("COLISEUM WINS")) == 0 ||
- strncmp(line, "VICROIRE DANS LE", LEN("VICTOIRES DANS LE")) == 0 ||
- strncmp(line, "VICTOIRES DANS LE COLISEE", LEN("VICTOIRES DANS LE COLISEE")) == 0) {
+ } else if (strncmp(line, "COLISEUM WINS", STRLEN("COLISEUM WINS")) == 0 ||
+ strncmp(line, "VICTOIRES DANS LE", STRLEN("VICTOIRES DANS LE")) == 0 ||
+ strncmp(line, "VICTOIRES DANS LE COLISEE", STRLEN("VICTOIRES DANS LE COLISEE")) == 0) {
player->coliseum = trim_stat(line);
- } else if (strncmp(line, "ITEMS UPGRADED", LEN("ITEMS UPGRADED")) == 0 ||
- strncmp(line, "OBJETS AMELIORES", LEN("OBJETS AMELIORES")) == 0) {
+ } else if (strncmp(line, "ITEMS UPGRADED", STRLEN("ITEMS UPGRADED")) == 0 ||
+ strncmp(line, "OBJETS AMELIORES", STRLEN("OBJETS AMELIORES")) == 0) {
player->items = trim_stat(line);
- } else if (strncmp(line, "FISH CAUGHT", LEN("FISH CAUGHT")) == 0 ||
- strncmp(line, "POISSONS ATTRAPES", LEN("POISSONS ATTRAPES")) == 0) {
+ } else if (strncmp(line, "FISH CAUGHT", STRLEN("FISH CAUGHT")) == 0 ||
+ strncmp(line, "POISSONS ATTRAPES", STRLEN("POISSONS ATTRAPES")) == 0) {
player->fish = trim_stat(line);
- } else if (strncmp(line, "DISTANCE TRAVELLED", LEN("DISTANCE TRAVELLED")) == 0 ||
- strncmp(line, "DISTANCE VOYAGEE", LEN("DISTANCE VOYAGEE")) == 0) {
+ } else if (strncmp(line, "DISTANCE TRAVELLED", STRLEN("DISTANCE TRAVELLED")) == 0 ||
+ strncmp(line, "DISTANCE VOYAGEE", STRLEN("DISTANCE VOYAGEE")) == 0) {
player->distance = trim_stat(line);
- } else if (strncmp(line, "REPUTATION", LEN("REPUTATION")) == 0) {
+ } else if (strncmp(line, "REPUTATION", STRLEN("REPUTATION")) == 0) {
player->reputation = trim_stat(line);
- } else if (strncmp(line, "ENDLESS RECORD", LEN("ENDLESS RECORD")) == 0 ||
- strncmp(line, "RECORD DU MODE", LEN("RECORD DU MODE")) == 0 ||
- strncmp(line, "RECORD DU MODE SANS-FIN", LEN("RECORD DU MODE SANS-FIN")) == 0) {
+ } else if (strncmp(line, "ENDLESS RECORD", STRLEN("ENDLESS RECORD")) == 0 ||
+ strncmp(line, "RECORD DU MODE", STRLEN("RECORD DU MODE")) == 0 ||
+ strncmp(line, "RECORD DU MODE SANS-FIN", STRLEN("RECORD DU MODE SANS-FIN")) == 0) {
player->endless = trim_stat(line);
- } else if (strncmp(line, "ENTRIES COMPLETED", LEN("ENTRIES COMPLETED")) == 0 ||
- strncmp(line, "RECHERCHES TERMINEES", LEN("RECHERCHES TERMINEES")) == 0) {
+ } else if (strncmp(line, "ENTRIES COMPLETED", STRLEN("ENTRIES COMPLETED")) == 0 ||
+ strncmp(line, "RECHERCHES TERMINEES", STRLEN("RECHERCHES TERMINEES")) == 0) {
player->codex = trim_stat(line);
}
}
@@ -262,7 +264,7 @@ create_player(Player *player, unsigned int i)
if (player->name)
players[i].name = strndup(player->name, MAX_USERNAME_LEN);
else
- players[i].name = strdup("placeholder");
+ players[i].name = strdup("placeholder"); /* FIXME */
players[i].kingdom = strndup(player->kingdom, MAX_KINGDOM_LEN);
for (j = 2; j < LENGTH(fields); j++)
((long *)&players[i])[j] = ((long *)player)[j];
@@ -295,8 +297,6 @@ update_player(char *buf, int siz, Player *player, unsigned int i)
/* -2 to not include update and userid */
for (j = 2; j < LENGTH(fields) - 2; j++) {
- if (siz <= 0)
- warn("nolan: string truncation in %s\n", __func__);
old = ((long *)&players[i])[j];
new = ((long *)player)[j];
diff = new - old;
@@ -328,9 +328,10 @@ update_player(char *buf, int siz, Player *player, unsigned int i)
/* update player */
((long *)&players[i])[j] = new;
}
-
+ if (siz <= 0)
+ WARN("string truncation");
if (!strftime(p, siz, "\nLast update was on %d %b %Y at %R UTC\n", tm))
- warn("nolan: strftime: string truncation in %s\n", __func__);
+ WARN("strftime: string truncation");
players[i].update = player->update;
/*
@@ -351,10 +352,8 @@ update_file(Player *player)
strlcpy(tmpfname, SAVE_FOLDER, sizeof(tmpfname));
strlcat(tmpfname, "tmpfile", sizeof(tmpfname));
- if ((r = fopen(STATS_FILE, "r")) == NULL)
- die("nolan: Failed to open %s\n", STATS_FILE);
- if ((w = fopen(tmpfname, "w")) == NULL)
- die("nolan: Failed to open %s\n", tmpfname);
+ r = efopen(STATS_FILE, "r");
+ w = efopen(tmpfname, "w");
while (fgets(line, LINE_SIZE, r)) {
endname = strchr(line, DELIM);
@@ -400,8 +399,7 @@ update_players(char *buf, size_t siz, Player *player)
if (i == nplayers) { /* new player */
nplayers++;
if (nplayers > MAX_PLAYERS)
- die("nolan: There is too much players (max:%d)\n",
- MAX_PLAYERS);
+ DIE("there is too much players (max:%lu)", MAX_PLAYERS);
create_player(player, i);
r = snprintf(buf, siz,
"**%s** has been registrated in the database.\n\n",
@@ -420,28 +418,27 @@ void
stats(char *buf, size_t siz, char *url, char *username, u64snowflake userid,
u64snowflake guild_id, struct discord *client)
{
- unsigned int i;
- char *txt, fname[128], lower_username[MAX_USERNAME_LEN];
+ unsigned int i, ret;
+ char *txt, fname[128];
Player player;
/* not always a jpg but idc */
snprintf(fname, sizeof(fname), "%s/%lu.jpg", IMAGES_FOLDER, userid);
- curl(url, fname);
- txt = ocr(fname, "eng");
- if (txt == NULL) {
- warn("nolan: Failed to read stats image\n");
+ if ((ret = curl(url, fname)) != 0) {
+ WARN("curl failed CURLcode:%u", ret);
+ strlcpy(buf, "Error: Failed to download image", siz);
+ return;
+ }
+ if ((txt = ocr(fname, "eng")) == NULL) {
+ WARN("failed to read image");
strlcpy(buf, "Error: Failed to read image", siz);
return;
}
memset(&player, 0, sizeof(player));
- if (username) {
- for (i = 0; i < strlen(username); i++)
- lower_username[i] = tolower(username[i]);
- lower_username[i] = '\0';
- player.name = lower_username;
- }
+ if (username)
+ player.name = username;
player.userid = userid;
player.update = time(NULL);
for_line(&player, txt);
@@ -500,20 +497,22 @@ on_stats_interaction(struct discord *client,
const struct discord_interaction *event)
{
char buf[MAX_MESSAGE_LEN] = "";
+ const cJSON *attachment = NULL, *url = NULL;
+ cJSON *attachments = cJSON_Parse(event->data->resolved->attachments);
- if (!event->data->resolved->attachments->array[0].url) {
- strlcpy(buf, "Error: For some reason the image was not loaded \
-correctly", sizeof(buf));
- } else {
- stats(buf,
- sizeof(buf),
- event->data->resolved->attachments->array[0].url,
- event->member->user->username,
- event->member->user->id,
- event->guild_id,
- client);
+ cJSON_ArrayForEach(attachment, attachments) {
+ url = cJSON_GetObjectItemCaseSensitive(attachment, "url");
}
+ stats(buf,
+ sizeof(buf),
+ url->valuestring,
+ event->member->user->username,
+ event->member->user->id,
+ event->guild_id,
+ client);
+ cJSON_Delete(attachments);
+
struct discord_interaction_response params = {
.type = DISCORD_INTERACTION_CHANNEL_MESSAGE_WITH_SOURCE,
.data = &(struct discord_interaction_callback_data)
@@ -531,26 +530,27 @@ on_stats_admin_interaction(struct discord *client,
const struct discord_interaction *event)
{
char buf[MAX_MESSAGE_LEN] = "";
+ const cJSON *attachment = NULL, *url = NULL;
+ cJSON *attachments = cJSON_Parse(event->data->resolved->attachments);
u64snowflake userid = str_to_uid(event->data->options->array[1].value);
- fprintf(stderr, "%s\n", event->data->resolved->attachments->array[0].url);
- fprintf(stderr, "%s\n", event->data->options->array[1].value);
+ cJSON_ArrayForEach(attachment, attachments) {
+ url = cJSON_GetObjectItemCaseSensitive(attachment, "url");
+ }
- if (!event->data->resolved->attachments->array[0].url) {
- strlcpy(buf, "Error: For some reason the image was not loaded \
-correctly", sizeof(buf));
- } else if (!userid) {
+ if (!userid) {
strlcpy(buf, "Error: This is probably not a correct user",
sizeof(buf));
} else {
stats(buf,
sizeof(buf),
- event->data->resolved->attachments->array[0].url,
+ url->valuestring,
NULL,
userid,
event->guild_id,
client);
}
+ cJSON_Delete(attachments);
struct discord_interaction_response params = {
.type = DISCORD_INTERACTION_CHANNEL_MESSAGE_WITH_SOURCE,
diff --git a/src/util.c b/src/util.c
index d241745..a73dbe7 100644
--- a/src/util.c
+++ b/src/util.c
@@ -1,33 +1,8 @@
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include "util.h"
-void
-warn(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-}
-
-void
-die(const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vfprintf(stderr, fmt, ap);
- va_end(ap);
-
- exit(EXIT_FAILURE);
-}
-
char *
nstrchr(const char *s, int c, int n)
{
@@ -69,7 +44,7 @@ strlcat(char *dst, const char *src, size_t siz)
}
int
-file_exists(char *filename)
+file_exists(const char *filename)
{
struct stat buf;
return (stat(filename, &buf) == 0);
@@ -81,16 +56,16 @@ emalloc(size_t size)
void *p;
if ((p = malloc(size)) == NULL)
- die("malloc failed\n");
+ DIE("malloc failed");
return p;
}
-void *
-ecalloc(size_t nmemb, size_t size)
+FILE *
+efopen(const char *filename, const char *modes)
{
- void *p;
+ FILE *fp;
- if ((p = calloc(nmemb, size)) == NULL)
- die("calloc failed\n");
- return p;
+ if ((fp = fopen(filename, modes)) == NULL)
+ DIE("failed to open %s (%s)", filename, modes);
+ return fp;
}
diff --git a/src/util.h b/src/util.h
index 073c849..8b8b935 100644
--- a/src/util.h
+++ b/src/util.h
@@ -1,12 +1,28 @@
-#define LENGTH(X) (sizeof(X) / sizeof(X[0]))
-#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
-#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#define LENGTH(X) (sizeof(X) / sizeof(X[0]))
+#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+#define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#define __EPRINTF(...) ((fprintf(stderr,\
+ "\033[1m%s:%d: %s: ",\
+ __FILE__,\
+ __LINE__,\
+ __func__)),\
+ (fprintf(stderr, __VA_ARGS__)),\
+ (fprintf(stderr, "\033[m\n")))
+#define WARN(...) (__EPRINTF("\033[35;1mwarning:\033[39;1m " __VA_ARGS__))
+#define DIE(...) (__EPRINTF("\033[31;1merror:\033[39;1m " __VA_ARGS__),\
+ exit(EXIT_FAILURE))
-void warn(const char *fmt, ...);
-void die(const char *fmt, ...);
char *nstrchr(const char *s, int c, int n);
size_t strlcpy(char *dst, const char *src, size_t siz);
size_t strlcat(char *dst, const char *src, size_t siz);
-int file_exists(char *filename);
+int file_exists(const char *filename);
void *emalloc(size_t size);
-void *ecalloc(size_t nmemb, size_t size);
+FILE *efopen(const char *filename, const char *modes);
+
+#endif /* UTIL_H */