Handle base error codes

This commit is contained in:
x3 2022-01-10 20:40:38 +01:00
parent 605f47f761
commit 09c8a57a78
Signed by: x3
GPG Key ID: 7E9961E8AD0E240E
4 changed files with 379 additions and 184 deletions

358
src/api.c
View File

@ -1,5 +1,6 @@
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <stdarg.h>
#include <assert.h> #include <assert.h>
#include <printf.h> #include <printf.h>
#include <time.h> #include <time.h>
@ -31,16 +32,9 @@
#error "No monotonic clock" #error "No monotonic clock"
#endif #endif
#define MS_TO_TIMESPEC(ts, ms) { \ static enum error api_cmd_base(char buffer[API_BUFSIZE],
ts->tv_sec = ms / 1000; \ struct api_result *res, const char *fmt, ...)
ts->tv_nsec = (ms % 1000) * 1000000; \ __attribute__((format (printf, 3, 4)));
}
#define MS_TO_TIMESPEC_L(ts, ms) { \
ts.tv_sec = ms / 1000; \
ts.tv_nsec = (ms % 1000) * 1000000; \
}
static enum error api_cmd_logout(struct api_result *res); static enum error api_cmd_logout(struct api_result *res);
static enum error api_cmd_auth(const char *uname, const char *pass, static enum error api_cmd_auth(const char *uname, const char *pass,
struct api_result *res); struct api_result *res);
@ -53,12 +47,14 @@ static bool api_encryption = false;
static pthread_t api_ka_thread = 0; static pthread_t api_ka_thread = 0;
static pthread_mutex_t api_work_mx; static pthread_mutex_t api_work_mx;
static bool api_ka_now = false; /* Are we doing keepalive now? */
static struct timespec api_last_packet = {0}; /* Last packet time */ static struct timespec api_last_packet = {0}; /* Last packet time */
static int32_t api_packet_count = 0; /* Only increment */ static int32_t api_packet_count = 0; /* Only increment */
//static int32_t api_fast_packet_count = 0; /* Increment or decrement */ //static int32_t api_fast_packet_count = 0; /* Increment or decrement */
/* For some commands, we need a global retry counter */
static int32_t api_g_retry_count = 0;
static int api_escaped_string(FILE *io, const struct printf_info *info, static int api_escaped_string(FILE *io, const struct printf_info *info,
const void *const *args) const void *const *args)
{ {
@ -186,16 +182,29 @@ static size_t api_decrypt(char *buffer, size_t data_len)
return ret_len; return ret_len;
} }
static enum error api_auth(const char* uname, const char *passw) static enum error api_auth()
{ {
struct api_result res; struct api_result res;
enum error err = NOERR; enum error err = NOERR;
char **uname, **passw;
if (config_get("username", (void**)&uname) != NOERR) {
uio_error("Username is not specified, but it is required!");
return ERR_OPT_REQUIRED;
}
if (config_get("password", (void**)&passw) != NOERR) {
uio_error("Password is not specified, but it is required!");
return ERR_OPT_REQUIRED;
}
/*
* We could try passing in a session key, if we are executing
* a login in response to a nologin or inv session error code?
*/
if (!api_encryption) if (!api_encryption)
uio_warning("Logging in without encryption!"); uio_warning("Logging in without encryption!");
if (api_cmd_auth(uname, passw, &res) != NOERR) { if (api_cmd_auth(*uname, *passw, &res) != NOERR)
return ERR_API_AUTH_FAIL; return ERR_API_AUTH_FAIL;
}
switch (res.code) { switch (res.code) {
case 201: case 201:
@ -218,12 +227,6 @@ static enum error api_auth(const char* uname, const char *passw)
uio_error("Client is banned :( Reason: %s", res.auth.banned_reason); uio_error("Client is banned :( Reason: %s", res.auth.banned_reason);
free(res.auth.banned_reason); free(res.auth.banned_reason);
break; break;
case 505:
uio_error("Illegal input or access denied");
break;
case 601:
uio_error("AniDB out of service");
break;
default: default:
uio_error("Unknown error: %hu", res.code); uio_error("Unknown error: %hu", res.code);
break; break;
@ -301,13 +304,11 @@ void *api_keepalive_main(void *arg)
* Could be replaced with a pthread_cleanup_push ? */ * Could be replaced with a pthread_cleanup_push ? */
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
pthread_mutex_lock(&api_work_mx); pthread_mutex_lock(&api_work_mx);
api_ka_now = true;
uio_debug("G'moooooning! Is it time to keep our special connection alive?"); uio_debug("G'moooooning! Is it time to keep our special connection alive?");
api_keepalive(&ka_time); api_keepalive(&ka_time);
uio_debug("Next wakey-wakey in %ld seconds", ka_time.tv_sec); uio_debug("Next wakey-wakey in %ld seconds", ka_time.tv_sec);
api_ka_now = false;
pthread_mutex_unlock(&api_work_mx); pthread_mutex_unlock(&api_work_mx);
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
} }
@ -333,7 +334,7 @@ enum error api_clock_init()
enum error api_init(bool auth) enum error api_init(bool auth)
{ {
enum error err = NOERR; enum error err = NOERR;
const char **api_key, **uname, **passwd; const char **api_key, **uname;
err = api_clock_init(); err = api_clock_init();
if (err != NOERR) if (err != NOERR)
@ -352,6 +353,7 @@ enum error api_init(bool auth)
} }
err = api_init_encrypt(*api_key, *uname); err = api_init_encrypt(*api_key, *uname);
if (err != NOERR) { if (err != NOERR) {
if (err != ERR_SHOULD_EXIT)
uio_error("Cannot init api encryption"); uio_error("Cannot init api encryption");
goto fail; goto fail;
} }
@ -366,26 +368,24 @@ enum error api_init(bool auth)
} }
if (auth) { if (auth) {
if (config_get("username", (void**)&uname) != NOERR) { pthread_mutexattr_t attr;
uio_error("Username is not specified, but it is required!"); int mxres;
err = ERR_OPT_REQUIRED;
goto fail; err = api_auth();
}
if (config_get("password", (void**)&passwd) != NOERR) {
uio_error("Password is not specified, but it is required!");
err = ERR_OPT_REQUIRED;
goto fail;
}
err = api_auth(*uname, *passwd);
if (err != NOERR) if (err != NOERR)
goto fail; goto fail;
/* Only do keep alive if we have a session */ /* Only do keep alive if we have a session */
if (pthread_mutex_init(&api_work_mx, NULL) != 0) { pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
mxres = pthread_mutex_init(&api_work_mx, NULL);
pthread_mutexattr_destroy(&attr);
if (mxres != 0) {
uio_error("Cannot create mutex"); uio_error("Cannot create mutex");
err = ERR_THRD; err = ERR_THRD;
goto fail; goto fail;
} }
if (pthread_create(&api_ka_thread, NULL, api_keepalive_main, NULL) != 0) { if (pthread_create(&api_ka_thread, NULL, api_keepalive_main, NULL) != 0) {
uio_error("Cannot create api keepalive thread"); uio_error("Cannot create api keepalive thread");
err = ERR_THRD; err = ERR_THRD;
@ -577,16 +577,76 @@ static char *api_get_field_mod(char *buffer, int32_t field_num)
} }
#endif #endif
static enum error api_cmd_encrypt(const char *uname, struct api_result *res) /* Basically convert remote codes into local error codes */
static enum error api_cmd_base_errorc(long code, char buffer[API_BUFSIZE])
{ {
pthread_mutex_lock(&api_work_mx); switch (code) {
char buffer[API_BUFSIZE]; case APICODE_ILLEGAL_INPUT_OR_ACCESS_DENIED:
long code; uio_error("Got unretryable error code: %d", code);
return ERR_API_INVCOMM;
case APICODE_BANNED:
{
char *ls;
size_t ll;
api_get_line(buffer, 2, &ls, &ll);
uio_error("Banned: %.*s", (int)ll, ls);
return ERR_API_BANNED;
}
case APICODE_UNKNOWN_COMMAND:
uio_error("The sent command is unknown");
return ERR_API_CMD_UNK;
case APICODE_INTERNAL_SERVER_ERROR:
uio_error("Internal server error!");
return ERR_API_INT_SRV;
case APICODE_ANIDB_OUT_OF_SERVICE:
uio_error("AniDB is currently out of service");
return ERR_API_OOS;
case APICODE_SERVER_BUSY:
uio_warning("Server is busy rn, trying again later");
return ERR_API_SRV_BUSY;
case APICODE_TIMEOUT:
uio_debug("Timed out, retrying");
return ERR_API_TIMEOUT;
case APICODE_LOGIN_FIRST:
uio_error("This command required AUTH");
return ERR_API_NOLOGIN;
case APICODE_ACCESS_DENIED:
uio_error("Access is denied for this info");
return ERR_API_AXX_DENIED;
case APICODE_INVALID_SESSION:
uio_error("The login session is invalid");
return ERR_API_INV_SESSION;
default:
/* Not an error, or at least not a base error */
return NOERR;
}
}
/*
* Base for all api_cmd's. This will also execute the default
* error code handers, like 505, 555, 604...
* If success, res.code will be filled out
*/
static enum error api_cmd_base(char buffer[API_BUFSIZE], struct api_result *res,
const char *fmt, ...)
{
int send_len;
enum error err = NOERR; enum error err = NOERR;
/* Usernames can't contain '&' */ va_list ap;
ssize_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer), int retry_count = 0;
"ENCRYPT user=%s&type=1", uname),
sizeof(buffer)); va_start(ap, fmt);
send_len = vsnprintf(buffer, API_BUFSIZE, fmt, ap);
va_end(ap);
pthread_mutex_lock(&api_work_mx);
api_g_retry_count = 0;
while (retry_count < API_MAX_TRYAGAIN &&
api_g_retry_count < API_MAX_TRYAGAIN) {
long code;
ssize_t res_len = api_send(buffer, send_len, API_BUFSIZE);
if (res_len < 0) { if (res_len < 0) {
if (res_len == -2 && should_exit) if (res_len == -2 && should_exit)
@ -601,8 +661,62 @@ static enum error api_cmd_encrypt(const char *uname, struct api_result *res)
err = ERR_API_RESP_INVALID; err = ERR_API_RESP_INVALID;
goto end; goto end;
} }
res->code = code;
if (code == 209) { err = api_cmd_base_errorc(code, buffer);
if (err == ERR_API_OOS || err == ERR_API_SRV_BUSY ||
err == ERR_API_TIMEOUT) {
struct timespec ts;
MS_TO_TIMESPEC_L(ts, API_TRYAGAIN_TIME);
retry_count++;
uio_debug("Retry after %ld ms (%d/%d)", API_TRYAGAIN_TIME,
retry_count, API_MAX_TRYAGAIN);
if (nanosleep(&ts, NULL) == -1) {
if (errno == EINTR && should_exit) {
err = ERR_SHOULD_EXIT;
goto end;
}
}
continue;
}
if (err == ERR_API_NOLOGIN || err == ERR_API_INV_SESSION) {
api_g_retry_count++;
if (api_g_retry_count < API_MAX_TRYAGAIN) {
uio_debug("Let's try loggin in agane");
api_authed = false; /* We got logged out probably */
err = api_auth(); /* -> will call this function */
if (api_g_retry_count < API_MAX_TRYAGAIN)
continue;
}
break;
}
break;
};
if (retry_count >= API_MAX_TRYAGAIN ||
api_g_retry_count >= API_MAX_TRYAGAIN) {
uio_debug("Max retry count reached");
goto end;
}
end:
pthread_mutex_unlock(&api_work_mx);
return err;
}
static enum error api_cmd_encrypt(const char *uname, struct api_result *res)
{
char buffer[API_BUFSIZE];
enum error err;
/* Usernames can't contain '&' */
err = api_cmd_base(buffer, res, "ENCRYPT user=%s&type=1", uname);
if (err != NOERR)
return err;
if (res->code == APICODE_ENCRYPTION_ENABLED) {
char *fs; char *fs;
size_t fl; size_t fl;
bool gfl = api_get_field(buffer, 2, &fs, &fl); bool gfl = api_get_field(buffer, 2, &fs, &fl);
@ -614,36 +728,19 @@ static enum error api_cmd_encrypt(const char *uname, struct api_result *res)
res->encrypt.salt[fl] = '\0'; res->encrypt.salt[fl] = '\0';
} }
res->code = (uint16_t)code;
end:
pthread_mutex_unlock(&api_work_mx);
return err; return err;
} }
enum error api_cmd_version(struct api_result *res) enum error api_cmd_version(struct api_result *res)
{ {
char buffer[API_BUFSIZE] = "VERSION"; char buffer[API_BUFSIZE];
ssize_t res_len = api_send(buffer, strlen(buffer), sizeof(buffer)); enum error err;
long code;
enum error err = NOERR;
pthread_mutex_lock(&api_work_mx);
if (res_len < 0) { err = api_cmd_base(buffer, res, "VERSION");
if (res_len == -2 && should_exit) if (err != NOERR)
err = ERR_SHOULD_EXIT; return err;
else
err = ERR_API_COMMFAIL;
goto end;
}
code = api_res_code(buffer); if (res->code == APICODE_VERSION) {
if (code == -1) {
err = ERR_API_RESP_INVALID;
goto end;
}
if (code == 998) {
char *ver_start; char *ver_start;
size_t ver_len; size_t ver_len;
bool glr = api_get_line(buffer, 2, &ver_start, &ver_len); bool glr = api_get_line(buffer, 2, &ver_start, &ver_len);
@ -654,40 +751,24 @@ enum error api_cmd_version(struct api_result *res)
memcpy(res->version.version_str, ver_start, ver_len); memcpy(res->version.version_str, ver_start, ver_len);
res->version.version_str[ver_len] = '\0'; res->version.version_str[ver_len] = '\0';
} }
res->code = (uint16_t)code;
end:
pthread_mutex_unlock(&api_work_mx);
return err; return err;
} }
static enum error api_cmd_auth(const char *uname, const char *pass, static enum error api_cmd_auth(const char *uname, const char *pass,
struct api_result *res) struct api_result *res)
{ {
pthread_mutex_lock(&api_work_mx);
char buffer[API_BUFSIZE]; char buffer[API_BUFSIZE];
long code; enum error err;
enum error err = NOERR;
ssize_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer),
"AUTH user=%s&pass=%B&protover=" API_VERSION "&client=caniadd&"
"clientver=" PROG_VERSION "&enc=UTF-8", uname, pass),
sizeof(buffer));
if (res_len < 0) { err = api_cmd_base(buffer, res, "AUTH user=%s&pass=%B&protover="
if (res_len == -2 && should_exit) API_VERSION "&client=caniadd&clientver=" PROG_VERSION
err = ERR_SHOULD_EXIT; "&enc=UTF-8", uname, pass);
else if (err != NOERR)
err = ERR_API_COMMFAIL; return err;
goto end;
}
code = api_res_code(buffer); if (res->code == APICODE_LOGIN_ACCEPTED ||
if (code == -1) { res->code == APICODE_LOGIN_ACCEPTED_NEW_VERSION) {
err = ERR_API_RESP_INVALID;
goto end;
}
if (code == 200 || code == 201) {
char *sess; char *sess;
size_t sess_len; size_t sess_len;
bool gfr = api_get_field(buffer, 2, &sess, &sess_len); bool gfr = api_get_field(buffer, 2, &sess, &sess_len);
@ -697,7 +778,7 @@ static enum error api_cmd_auth(const char *uname, const char *pass,
assert(sess_len < sizeof(res->auth.session_key)); assert(sess_len < sizeof(res->auth.session_key));
memcpy(res->auth.session_key, sess, sess_len); memcpy(res->auth.session_key, sess, sess_len);
res->auth.session_key[sess_len] = '\0'; res->auth.session_key[sess_len] = '\0';
} else if (code == 504) { } else if (res->code == APICODE_CLIENT_BANNED) {
char *reason; char *reason;
size_t reason_len; size_t reason_len;
bool gfr = api_get_field(buffer, 5, &reason, &reason_len); bool gfr = api_get_field(buffer, 5, &reason, &reason_len);
@ -706,70 +787,32 @@ static enum error api_cmd_auth(const char *uname, const char *pass,
(void)gfr; (void)gfr;
res->auth.banned_reason = strndup(reason, reason_len); res->auth.banned_reason = strndup(reason, reason_len);
} }
res->code = (uint16_t)code;
end:
pthread_mutex_unlock(&api_work_mx);
return err; return err;
} }
static enum error api_cmd_logout(struct api_result *res) static enum error api_cmd_logout(struct api_result *res)
{ {
pthread_mutex_lock(&api_work_mx);
char buffer[API_BUFSIZE]; char buffer[API_BUFSIZE];
ssize_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer), enum error err;
"LOGOUT s=%s", api_session), sizeof(buffer));
long code;
enum error err = NOERR;
if (res_len < 0) { err = api_cmd_base(buffer, res, "LOGOUT s=%s", api_session);
if (res_len == -2 && should_exit) if (err != NOERR)
err = ERR_SHOULD_EXIT; return err;
else
err = ERR_API_COMMFAIL;
goto end;
}
code = api_res_code(buffer);
if (code == -1) {
err = ERR_API_RESP_INVALID;
goto end;
}
res->code = (uint16_t)code;
end:
pthread_mutex_unlock(&api_work_mx);
return err; return err;
} }
enum error api_cmd_uptime(struct api_result *res) enum error api_cmd_uptime(struct api_result *res)
{ {
/* If mutex is not already locked from the keepalive thread */
/* Or we could use a recursive mutex? */
if (!api_ka_now)
pthread_mutex_lock(&api_work_mx);
char buffer[API_BUFSIZE]; char buffer[API_BUFSIZE];
ssize_t res_len = api_send(buffer, snprintf(buffer, sizeof(buffer), enum error err;
"UPTIME s=%s", api_session), sizeof(buffer));
long code;
enum error err = NOERR;
if (res_len < 0) { err = api_cmd_base(buffer, res, "UPTIME s=%s", api_session);
if (res_len == -2 && should_exit) if (err != NOERR)
err = ERR_SHOULD_EXIT; return err;
else
err = ERR_API_COMMFAIL;
goto end;
}
code = api_res_code(buffer); if (res->code == APICODE_UPTIME) {
if (code == -1) {
err = ERR_API_RESP_INVALID;
goto end;
}
if (code == 208) {
char *ls; char *ls;
size_t ll; size_t ll;
bool glf = api_get_line(buffer, 2, &ls, &ll); bool glf = api_get_line(buffer, 2, &ls, &ll);
@ -779,11 +822,6 @@ enum error api_cmd_uptime(struct api_result *res)
res->uptime.ms = strtol(ls, NULL, 10); res->uptime.ms = strtol(ls, NULL, 10);
} }
res->code = (uint16_t)code;
end:
if (!api_ka_now)
pthread_mutex_unlock(&api_work_mx);
return err; return err;
} }
@ -792,33 +830,17 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash,
{ {
char buffer[API_BUFSIZE]; char buffer[API_BUFSIZE];
char hash_str[ED2K_HASH_SIZE * 2 + 1]; char hash_str[ED2K_HASH_SIZE * 2 + 1];
ssize_t res_len;
enum error err = NOERR; enum error err = NOERR;
long code;
pthread_mutex_lock(&api_work_mx);
util_byte2hex(hash, ED2K_HASH_SIZE, false, hash_str); util_byte2hex(hash, ED2K_HASH_SIZE, false, hash_str);
/* Wiki says file size is 4 bytes, but no way that's true lol */ /* Wiki says file size is 4 bytes, but no way that's true lol */
res_len = api_send(buffer, snprintf(buffer, sizeof(buffer), err = api_cmd_base(buffer, res,
"MYLISTADD s=%s&size=%ld&ed2k=%s&state=%hu&viewed=%d", "MYLISTADD s=%s&size=%ld&ed2k=%s&state=%hu&viewed=%d",
api_session, size, hash_str, ml_state, watched), api_session, size, hash_str, ml_state, watched);
sizeof(buffer)); if (err != NOERR)
return err;
if (res_len < 0) { if (res->code == APICODE_MYLIST_ENTRY_ADDED) {
if (res_len == -2 && should_exit)
err = ERR_SHOULD_EXIT;
else
err = ERR_API_COMMFAIL;
goto end;
}
code = api_res_code(buffer);
if (code == -1) {
err = ERR_API_RESP_INVALID;
goto end;
}
if (code == 210) {
char *ls, id_str[12]; char *ls, id_str[12];
size_t ll; size_t ll;
bool glr = api_get_line(buffer, 2, &ls, &ll); bool glr = api_get_line(buffer, 2, &ls, &ll);
@ -832,7 +854,7 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash,
/* Wiki says these id's are 4 bytes, which is untrue... /* Wiki says these id's are 4 bytes, which is untrue...
* that page may be a little out of date (or they just * that page may be a little out of date (or they just
* expect us to use common sense lmao */ * expect us to use common sense lmao */
} else if (code == 310) { } else if (res->code == APICODE_FILE_ALREADY_IN_MYLIST) {
/* {int4 lid}|{int4 fid}|{int4 eid}|{int4 aid}|{int4 gid}| /* {int4 lid}|{int4 fid}|{int4 eid}|{int4 aid}|{int4 gid}|
* {int4 date}|{int2 state}|{int4 viewdate}|{str storage}| * {int4 date}|{int2 state}|{int4 viewdate}|{str storage}|
* {str source}|{str other}|{int2 filestate} */ * {str source}|{str other}|{int2 filestate} */
@ -880,10 +902,6 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash,
} }
} }
res->code = (uint16_t)code;
end:
pthread_mutex_unlock(&api_work_mx);
return err; return err;
} }

157
src/api.h
View File

@ -25,6 +25,163 @@
/* After this many packets has been sent, use the longterm ratelimit */ /* After this many packets has been sent, use the longterm ratelimit */
#define API_LONGTERM_PACKETS 100 #define API_LONGTERM_PACKETS 100
/* How much to wait between try agains? in ms */
#define API_TRYAGAIN_TIME 60 * 1000
#define API_MAX_TRYAGAIN 5
enum api_code {
APICODE_LOGIN_ACCEPTED = 200,
APICODE_LOGIN_ACCEPTED_NEW_VERSION = 201,
APICODE_LOGGED_OUT = 203,
APICODE_RESOURCE = 205,
APICODE_STATS = 206,
APICODE_TOP = 207,
APICODE_UPTIME = 208,
APICODE_ENCRYPTION_ENABLED = 209,
APICODE_MYLIST_ENTRY_ADDED = 210,
APICODE_MYLIST_ENTRY_DELETED = 211,
APICODE_ADDED_FILE = 214,
APICODE_ADDED_STREAM = 215,
APICODE_EXPORT_QUEUED = 217,
APICODE_EXPORT_CANCELLED = 218,
APICODE_ENCODING_CHANGED = 219,
APICODE_FILE = 220,
APICODE_MYLIST = 221,
APICODE_MYLIST_STATS = 222,
APICODE_WISHLIST = 223,
APICODE_NOTIFICATION = 224,
APICODE_GROUP_STATUS = 225,
APICODE_WISHLIST_ENTRY_ADDED = 226,
APICODE_WISHLIST_ENTRY_DELETED = 227,
APICODE_WISHLIST_ENTRY_UPDATED = 228,
APICODE_MULTIPLE_WISHLIST = 229,
APICODE_ANIME = 230,
APICODE_ANIME_BEST_MATCH = 231,
APICODE_RANDOM_ANIME = 232,
APICODE_ANIME_DESCRIPTION = 233,
APICODE_REVIEW = 234,
APICODE_CHARACTER = 235,
APICODE_SONG = 236,
APICODE_ANIMETAG = 237,
APICODE_CHARACTERTAG = 238,
APICODE_EPISODE = 240,
APICODE_UPDATED = 243,
APICODE_TITLE = 244,
APICODE_CREATOR = 245,
APICODE_NOTIFICATION_ENTRY_ADDED = 246,
APICODE_NOTIFICATION_ENTRY_DELETED = 247,
APICODE_NOTIFICATION_ENTRY_UPDATE = 248,
APICODE_MULTIPLE_NOTIFICATION = 249,
APICODE_GROUP = 250,
APICODE_CATEGORY = 251,
APICODE_BUDDY_LIST = 253,
APICODE_BUDDY_STATE = 254,
APICODE_BUDDY_ADDED = 255,
APICODE_BUDDY_DELETED = 256,
APICODE_BUDDY_ACCEPTED = 257,
APICODE_BUDDY_DENIED = 258,
APICODE_VOTED = 260,
APICODE_VOTE_FOUND = 261,
APICODE_VOTE_UPDATED = 262,
APICODE_VOTE_REVOKED = 263,
APICODE_HOT_ANIME = 265,
APICODE_RANDOM_RECOMMENDATION = 266,
APICODE_RANDOM_SIMILAR = 267,
APICODE_NOTIFICATION_ENABLED = 270,
APICODE_NOTIFYACK_SUCCESSFUL_MESSAGE = 281,
APICODE_NOTIFYACK_SUCCESSFUL_NOTIFICATION = 282,
APICODE_NOTIFICATION_STATE = 290,
APICODE_NOTIFYLIST = 291,
APICODE_NOTIFYGET_MESSAGE = 292,
APICODE_NOTIFYGET_NOTIFY = 293,
APICODE_SENDMESSAGE_SUCCESSFUL = 294,
APICODE_USER_ID = 295,
APICODE_CALENDAR = 297,
APICODE_PONG = 300,
APICODE_AUTHPONG = 301,
APICODE_NO_SUCH_RESOURCE = 305,
APICODE_API_PASSWORD_NOT_DEFINED = 309,
APICODE_FILE_ALREADY_IN_MYLIST = 310,
APICODE_MYLIST_ENTRY_EDITED = 311,
APICODE_MULTIPLE_MYLIST_ENTRIES = 312,
APICODE_WATCHED = 313,
APICODE_SIZE_HASH_EXISTS = 314,
APICODE_INVALID_DATA = 315,
APICODE_STREAMNOID_USED = 316,
APICODE_EXPORT_NO_SUCH_TEMPLATE = 317,
APICODE_EXPORT_ALREADY_IN_QUEUE = 318,
APICODE_EXPORT_NO_EXPORT_QUEUED_OR_IS_PROCESSING = 319,
APICODE_NO_SUCH_FILE = 320,
APICODE_NO_SUCH_ENTRY = 321,
APICODE_MULTIPLE_FILES_FOUND = 322,
APICODE_NO_SUCH_WISHLIST = 323,
APICODE_NO_SUCH_NOTIFICATION = 324,
APICODE_NO_GROUPS_FOUND = 325,
APICODE_NO_SUCH_ANIME = 330,
APICODE_NO_SUCH_DESCRIPTION = 333,
APICODE_NO_SUCH_REVIEW = 334,
APICODE_NO_SUCH_CHARACTER = 335,
APICODE_NO_SUCH_SONG = 336,
APICODE_NO_SUCH_ANIMETAG = 337,
APICODE_NO_SUCH_CHARACTERTAG = 338,
APICODE_NO_SUCH_EPISODE = 340,
APICODE_NO_SUCH_UPDATES = 343,
APICODE_NO_SUCH_TITLES = 344,
APICODE_NO_SUCH_CREATOR = 345,
APICODE_NO_SUCH_GROUP = 350,
APICODE_NO_SUCH_CATEGORY = 351,
APICODE_BUDDY_ALREADY_ADDED = 355,
APICODE_NO_SUCH_BUDDY = 356,
APICODE_BUDDY_ALREADY_ACCEPTED = 357,
APICODE_BUDDY_ALREADY_DENIED = 358,
APICODE_NO_SUCH_VOTE = 360,
APICODE_INVALID_VOTE_TYPE = 361,
APICODE_INVALID_VOTE_VALUE = 362,
APICODE_PERMVOTE_NOT_ALLOWED = 363,
APICODE_ALREADY_PERMVOTED = 364,
APICODE_HOT_ANIME_EMPTY = 365,
APICODE_RANDOM_RECOMMENDATION_EMPTY = 366,
APICODE_RANDOM_SIMILAR_EMPTY = 367,
APICODE_NOTIFICATION_DISABLED = 370,
APICODE_NO_SUCH_ENTRY_MESSAGE = 381,
APICODE_NO_SUCH_ENTRY_NOTIFICATION = 382,
APICODE_NO_SUCH_MESSAGE = 392,
APICODE_NO_SUCH_NOTIFY = 393,
APICODE_NO_SUCH_USER = 394,
APICODE_CALENDAR_EMPTY = 397,
APICODE_NO_CHANGES = 399,
APICODE_NOT_LOGGED_IN = 403,
APICODE_NO_SUCH_MYLIST_FILE = 410,
APICODE_NO_SUCH_MYLIST_ENTRY = 411,
APICODE_MYLIST_UNAVAILABLE = 412,
APICODE_LOGIN_FAILED = 500,
APICODE_LOGIN_FIRST = 501,
APICODE_ACCESS_DENIED = 502,
APICODE_CLIENT_VERSION_OUTDATED = 503,
APICODE_CLIENT_BANNED = 504,
APICODE_ILLEGAL_INPUT_OR_ACCESS_DENIED = 505,
APICODE_INVALID_SESSION = 506,
APICODE_NO_SUCH_ENCRYPTION_TYPE = 509,
APICODE_ENCODING_NOT_SUPPORTED = 519,
APICODE_BANNED = 555,
APICODE_UNKNOWN_COMMAND = 598,
APICODE_INTERNAL_SERVER_ERROR = 600,
APICODE_ANIDB_OUT_OF_SERVICE = 601,
APICODE_SERVER_BUSY = 602,
APICODE_NO_DATA = 603,
APICODE_TIMEOUT = 604,
APICODE_API_VIOLATION = 666,
APICODE_PUSHACK_CONFIRMED = 701,
APICODE_NO_SUCH_PACKET_PENDING = 702,
APICODE_VERSION = 998,
};
enum mylist_state { enum mylist_state {
MYLIST_STATE_UNKNOWN = 0, MYLIST_STATE_UNKNOWN = 0,
MYLIST_STATE_INTERNAL, MYLIST_STATE_INTERNAL,

View File

@ -35,6 +35,16 @@
E(ERR_API_LOGOUT) /* Logout failed */ \ E(ERR_API_LOGOUT) /* Logout failed */ \
E(ERR_API_PRINTFFUNC) /* New printf function registration failed */ \ E(ERR_API_PRINTFFUNC) /* New printf function registration failed */ \
E(ERR_API_CLOCK) /* Some error with clocks */ \ E(ERR_API_CLOCK) /* Some error with clocks */ \
E(ERR_API_INVCOMM) /* Invalid command or command arguments */ \
E(ERR_API_BANNED) /* Got banned */ \
E(ERR_API_CMD_UNK) /* Unknown command */ \
E(ERR_API_INT_SRV) /* Internal server error */ \
E(ERR_API_OOS) /* AniDB is out of service rn */ \
E(ERR_API_SRV_BUSY) /* Server is too busy, try again later */ \
E(ERR_API_TIMEOUT) /* Timed out, delay and resubmit */ \
E(ERR_API_NOLOGIN) /* Login is required for this command */ \
E(ERR_API_AXX_DENIED) /* Access is denied */ \
E(ERR_API_INV_SESSION) /* Session is invalid */ \
\ \
E(ERR_CACHE_SQLITE) /* Generic sqlite error code */ \ E(ERR_CACHE_SQLITE) /* Generic sqlite error code */ \
E(ERR_CACHE_EXISTS) /* Entry already exists, as determined by lid */ \ E(ERR_CACHE_EXISTS) /* Entry already exists, as determined by lid */ \

View File

@ -4,6 +4,16 @@
#include <stddef.h> #include <stddef.h>
#include <stdbool.h> #include <stdbool.h>
#define MS_TO_TIMESPEC(ts, ms) { \
ts->tv_sec = ms / 1000; \
ts->tv_nsec = (ms % 1000) * 1000000; \
}
#define MS_TO_TIMESPEC_L(ts, ms) { \
ts.tv_sec = ms / 1000; \
ts.tv_nsec = (ms % 1000) * 1000000; \
}
/* /*
* Convert bytes to a hex string * Convert bytes to a hex string
* out needs to be at least (bytes_len * 2 + 1) bytes * out needs to be at least (bytes_len * 2 + 1) bytes