@@ -677,18 +677,12 @@ static enum error api_cmd_base_errorc(long code, char buffer[API_BUFSIZE]) | |||||
* error code handers, like 505, 555, 604... | * error code handers, like 505, 555, 604... | ||||
* If success, res.code will be filled out | * 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, ...) | |||||
static enum error api_cmd_base_pref(char buffer[API_BUFSIZE], int send_len, | |||||
struct api_result *res) | |||||
{ | { | ||||
int send_len; | |||||
enum error err = NOERR; | enum error err = NOERR; | ||||
va_list ap; | |||||
int retry_count = 0; | int retry_count = 0; | ||||
va_start(ap, fmt); | |||||
send_len = vsnprintf(buffer, API_BUFSIZE, fmt, ap); | |||||
va_end(ap); | |||||
pthread_mutex_lock(&api_work_mx); | pthread_mutex_lock(&api_work_mx); | ||||
api_g_retry_count = 0; | api_g_retry_count = 0; | ||||
@@ -754,6 +748,18 @@ end: | |||||
pthread_mutex_unlock(&api_work_mx); | pthread_mutex_unlock(&api_work_mx); | ||||
return err; | return err; | ||||
} | } | ||||
static enum error api_cmd_base(char buffer[API_BUFSIZE], struct api_result *res, | |||||
const char *fmt, ...) | |||||
{ | |||||
va_list ap; | |||||
int send_len; | |||||
va_start(ap, fmt); | |||||
send_len = vsnprintf(buffer, API_BUFSIZE, fmt, ap); | |||||
va_end(ap); | |||||
return api_cmd_base_pref(buffer, send_len, res); | |||||
} | |||||
static enum error api_cmd_encrypt(const char *uname, struct api_result *res) | static enum error api_cmd_encrypt(const char *uname, struct api_result *res) | ||||
{ | { | ||||
@@ -875,17 +881,28 @@ enum error api_cmd_uptime(struct api_result *res) | |||||
} | } | ||||
enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash, | enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash, | ||||
enum mylist_state ml_state, bool watched, struct api_result *res) | |||||
struct api_mylistadd_opts *opts, struct api_result *res) | |||||
{ | { | ||||
char buffer[API_BUFSIZE]; | char buffer[API_BUFSIZE]; | ||||
char hash_str[ED2K_HASH_SIZE * 2 + 1]; | char hash_str[ED2K_HASH_SIZE * 2 + 1]; | ||||
enum error err = NOERR; | enum error err = NOERR; | ||||
int send_len; | |||||
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 */ | ||||
err = api_cmd_base(buffer, res, | |||||
"MYLISTADD s=%s&size=%ld&ed2k=%s&state=%hu&viewed=%d", | |||||
api_session, size, hash_str, ml_state, watched); | |||||
send_len = snprintf(buffer, sizeof(buffer), | |||||
"MYLISTADD s=%s&size=%ld&ed2k=%s", | |||||
api_session, size, hash_str); | |||||
if (opts->state_set) | |||||
send_len += snprintf(buffer + send_len, sizeof(buffer) - send_len, | |||||
"&state=%hu", opts->state); | |||||
if (opts->watched_set) | |||||
send_len += snprintf(buffer + send_len, sizeof(buffer) - send_len, | |||||
"&viewed=%d", opts->watched); | |||||
if (opts->wdate_set) | |||||
send_len += snprintf(buffer + send_len, sizeof(buffer) - send_len, | |||||
"&viewdate=%ld", opts->wdate); | |||||
err = api_cmd_base_pref(buffer, send_len, res); | |||||
if (err != NOERR) | if (err != NOERR) | ||||
return err; | return err; | ||||
@@ -939,4 +956,27 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash, | |||||
return err; | return err; | ||||
} | } | ||||
enum error api_cmd_mylistmod(uint64_t lid, struct api_mylistadd_opts *opts, | |||||
struct api_result *res) | |||||
{ | |||||
char buffer[API_BUFSIZE]; | |||||
enum error err = NOERR; | |||||
int send_len; | |||||
send_len = snprintf(buffer, sizeof(buffer), | |||||
"MYLISTADD s=%s&lid=%lu&edit=1", api_session, lid); | |||||
if (opts->state_set) | |||||
send_len += snprintf(buffer + send_len, sizeof(buffer) - send_len, | |||||
"&state=%hu", opts->state); | |||||
if (opts->watched_set) | |||||
send_len += snprintf(buffer + send_len, sizeof(buffer) - send_len, | |||||
"&viewed=%d", opts->watched); | |||||
if (opts->wdate_set) | |||||
send_len += snprintf(buffer + send_len, sizeof(buffer) - send_len, | |||||
"&viewdate=%ld", opts->wdate); | |||||
err = api_cmd_base_pref(buffer, send_len, res); | |||||
return err; | |||||
} | |||||
#pragma GCC diagnostic pop | #pragma GCC diagnostic pop |
@@ -203,6 +203,17 @@ enum file_state { | |||||
FILE_STATE_OTHER = 100, | FILE_STATE_OTHER = 100, | ||||
}; | }; | ||||
struct api_mylistadd_opts { | |||||
enum mylist_state state; | |||||
bool watched; | |||||
uint64_t wdate; | |||||
struct { | |||||
bool state_set : 1; | |||||
bool watched_set : 1; | |||||
bool wdate_set : 1; | |||||
}; | |||||
}; | |||||
struct api_version_result { | struct api_version_result { | ||||
char version_str[40]; | char version_str[40]; | ||||
}; | }; | ||||
@@ -231,6 +242,9 @@ struct api_mylistadd_result { | |||||
}; | }; | ||||
}; | }; | ||||
}; | }; | ||||
struct api_mylistmod_result { | |||||
uint32_t n_edits; | |||||
}; | |||||
#define e(n) struct api_##n##_result n | #define e(n) struct api_##n##_result n | ||||
struct api_result { | struct api_result { | ||||
@@ -241,6 +255,7 @@ struct api_result { | |||||
struct api_uptime_result uptime; | struct api_uptime_result uptime; | ||||
e(mylistadd); | e(mylistadd); | ||||
e(encrypt); | e(encrypt); | ||||
e(mylistmod); | |||||
}; | }; | ||||
}; | }; | ||||
#undef e | #undef e | ||||
@@ -251,6 +266,8 @@ void api_free(); | |||||
enum error api_cmd_version(struct api_result *res); | enum error api_cmd_version(struct api_result *res); | ||||
enum error api_cmd_uptime(struct api_result *res); | enum error api_cmd_uptime(struct api_result *res); | ||||
enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash, | enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash, | ||||
enum mylist_state fstate, bool watched, struct api_result *res); | |||||
struct api_mylistadd_opts *opts, struct api_result *res); | |||||
enum error api_cmd_mylistmod(uint64_t lid, struct api_mylistadd_opts *opts, | |||||
struct api_result *res); | |||||
#endif /* _API_H */ | #endif /* _API_H */ |
@@ -23,6 +23,7 @@ static const struct cmd_entry ents[] = { | |||||
{ .arg_name = "uptime", .fn = cmd_server_uptime, .need_auth = true }, | { .arg_name = "uptime", .fn = cmd_server_uptime, .need_auth = true }, | ||||
{ .arg_name = "ed2k", .fn = cmd_ed2k, }, | { .arg_name = "ed2k", .fn = cmd_ed2k, }, | ||||
{ .arg_name = "add", .fn = cmd_add, .need_auth = true, .need_cache = true, }, | { .arg_name = "add", .fn = cmd_add, .need_auth = true, .need_cache = true, }, | ||||
{ .arg_name = "modify", .fn = cmd_modify, .need_auth = true, .need_cache = false, }, | |||||
}; | }; | ||||
static const int32_t ents_len = sizeof(ents)/sizeof(*ents); | static const int32_t ents_len = sizeof(ents)/sizeof(*ents); | ||||
@@ -35,4 +35,9 @@ enum error cmd_server_uptime(void *); | |||||
*/ | */ | ||||
enum error cmd_prog_version(void *); | enum error cmd_prog_version(void *); | ||||
/* | |||||
* Modifies a mylist entry | |||||
*/ | |||||
enum error cmd_modify(void *data); | |||||
#endif /* _CMD_H */ | #endif /* _CMD_H */ |
@@ -12,11 +12,6 @@ | |||||
#include "cache.h" | #include "cache.h" | ||||
#include "util.h" | #include "util.h" | ||||
struct add_opts { | |||||
enum mylist_state ao_state; | |||||
bool ao_watched; | |||||
}; | |||||
enum error cmd_add_cachecheck(const char *path, const struct stat *st, | enum error cmd_add_cachecheck(const char *path, const struct stat *st, | ||||
void *data) | void *data) | ||||
{ | { | ||||
@@ -43,9 +38,9 @@ enum error cmd_add_apisend(const char *path, const uint8_t *hash, | |||||
const struct stat *st, void *data) | const struct stat *st, void *data) | ||||
{ | { | ||||
struct api_result r; | struct api_result r; | ||||
struct add_opts* ao = (struct add_opts*)data; | |||||
struct api_mylistadd_opts *mopt = (struct api_mylistadd_opts *)data; | |||||
if (api_cmd_mylistadd(st->st_size, hash, ao->ao_state, ao->ao_watched, &r) | |||||
if (api_cmd_mylistadd(st->st_size, hash, mopt, &r) | |||||
!= NOERR) | != NOERR) | ||||
return ERR_CMD_FAILED; | return ERR_CMD_FAILED; | ||||
@@ -83,13 +78,14 @@ enum error cmd_add_apisend(const char *path, const uint8_t *hash, | |||||
enum error cmd_add(void *data) | enum error cmd_add(void *data) | ||||
{ | { | ||||
struct add_opts add_opts = {0}; | |||||
struct api_mylistadd_opts mopt = {0}; | |||||
struct ed2k_util_opts ed2k_opts = { | struct ed2k_util_opts ed2k_opts = { | ||||
.pre_hash_fn = cmd_add_cachecheck, | .pre_hash_fn = cmd_add_cachecheck, | ||||
.post_hash_fn = cmd_add_apisend, | .post_hash_fn = cmd_add_apisend, | ||||
.data = &add_opts, | |||||
.data = &mopt, | |||||
}; | }; | ||||
bool *watched; | bool *watched; | ||||
const char **wdate_str; | |||||
enum error err = NOERR; | enum error err = NOERR; | ||||
int fcount; | int fcount; | ||||
@@ -99,10 +95,23 @@ enum error cmd_add(void *data) | |||||
return ERR_CMD_ARG; | return ERR_CMD_ARG; | ||||
} | } | ||||
if (config_get("watched", (void**)&watched) == NOERR) { | |||||
add_opts.ao_watched = *watched; | |||||
if (config_get("watched", (void**)&watched) == NOERR && *watched) { | |||||
mopt.watched = *watched; | |||||
mopt.watched_set = true; | |||||
if (config_get("wdate", (void**)&wdate_str) == NOERR) { | |||||
uint64_t wdate = util_iso2unix(*wdate_str); | |||||
if (wdate == 0) { | |||||
uio_error("Invalid time value: '%s'", *wdate_str); | |||||
return ERR_CMD_ARG; | |||||
} | |||||
mopt.wdate = wdate; | |||||
mopt.wdate_set = true; | |||||
} | |||||
} | } | ||||
add_opts.ao_state = MYLIST_STATE_INTERNAL; | |||||
mopt.state = MYLIST_STATE_INTERNAL; | |||||
mopt.state_set = true; | |||||
for (int i = 0; i < fcount; i++) { | for (int i = 0; i < fcount; i++) { | ||||
err = ed2k_util_iterpath(config_get_nonopt(i), &ed2k_opts); | err = ed2k_util_iterpath(config_get_nonopt(i), &ed2k_opts); | ||||
@@ -0,0 +1,65 @@ | |||||
#include <sys/stat.h> | |||||
#include <stdlib.h> | |||||
#include <stdio.h> | |||||
#include <stdbool.h> | |||||
#include "cmd.h" | |||||
#include "error.h" | |||||
#include "uio.h" | |||||
#include "api.h" | |||||
#include "config.h" | |||||
#include "ed2k_util.h" | |||||
#include "cache.h" | |||||
#include "util.h" | |||||
enum error cmd_modify(void *data) | |||||
{ | |||||
struct api_mylistadd_opts mopt = {0}; | |||||
bool *watched; | |||||
const char **wdate_str; | |||||
enum error err = NOERR; | |||||
int fcount; | |||||
fcount = config_get_nonopt_count(); | |||||
if (fcount == 0) { | |||||
uio_error("No mylist ids specified"); | |||||
return ERR_CMD_ARG; | |||||
} | |||||
if (config_get("watched", (void**)&watched) == NOERR && *watched) { | |||||
mopt.watched = *watched; | |||||
mopt.watched_set = true; | |||||
if (config_get("wdate", (void**)&wdate_str) == NOERR) { | |||||
uint64_t wdate = util_iso2unix(*wdate_str); | |||||
if (wdate == 0) { | |||||
uio_error("Invalid time value: '%s'", *wdate_str); | |||||
return ERR_CMD_ARG; | |||||
} | |||||
mopt.wdate = wdate; | |||||
mopt.wdate_set = true; | |||||
} | |||||
} | |||||
for (int i = 0; i < fcount; i++) { | |||||
struct api_result res; | |||||
uint64_t lid; | |||||
const char *arg = config_get_nonopt(i); | |||||
if (sscanf(arg, "%lu", &lid) != 1) { | |||||
uio_error("Argument '%s' is not an integer. Skipping", arg); | |||||
continue; | |||||
} | |||||
err = api_cmd_mylistmod(lid, &mopt, &res); | |||||
if (err != NOERR) | |||||
break; | |||||
if (res.code == APICODE_NO_SUCH_MYLIST_ENTRY) { | |||||
uio_error("No mylist entry with id: '%lu'", lid); | |||||
} | |||||
} | |||||
return err; | |||||
} | |||||
@@ -110,6 +110,10 @@ static struct conf_entry options[] = { | |||||
.set_func = config_set_bool, .in_args = true, .in_file = true, | .set_func = config_set_bool, .in_args = true, .in_file = true, | ||||
.type = OTYPE_B, .handle_order = 1, .value_is_set = true, }, | .type = OTYPE_B, .handle_order = 1, .value_is_set = true, }, | ||||
{ .l_name = "wdate", .s_name = UCHAR_MAX + 4, .has_arg = required_argument, | |||||
.set_func = config_set_str, .in_args = true, | |||||
.type = OTYPE_S, .handle_order = 1, }, | |||||
/*### cmd ###*/ | /*### cmd ###*/ | ||||
{ .l_name = "server-version", .s_name = UCHAR_MAX + 2, | { .l_name = "server-version", .s_name = UCHAR_MAX + 2, | ||||
@@ -132,7 +136,11 @@ static struct conf_entry options[] = { | |||||
.has_arg = no_argument, .set_func = config_set_bool, .in_args = true, | .has_arg = no_argument, .set_func = config_set_bool, .in_args = true, | ||||
.type = OTYPE_B, .handle_order = 1 }, | .type = OTYPE_B, .handle_order = 1 }, | ||||
/*{ .l_name = "stats", .s_name = UCHAR_MAX + 4, | |||||
{ .l_name = "modify", .s_name = 'W', | |||||
.has_arg = no_argument, .set_func = config_set_bool, .in_args = true, | |||||
.type = OTYPE_B, .handle_order = 1 }, | |||||
/*{ .l_name = "stats", .s_name = UCHAR_MAX + 5, | |||||
.has_arg = no_argument, .set_func = config_set_bool, .in_args = true, | .has_arg = no_argument, .set_func = config_set_bool, .in_args = true, | ||||
.type = OTYPE_B, .handle_order = 1, .value_is_set = true },*/ | .type = OTYPE_B, .handle_order = 1, .value_is_set = true },*/ | ||||
@@ -1,5 +1,7 @@ | |||||
#define _XOPEN_SOURCE | |||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <time.h> | |||||
#include "util.h" | #include "util.h" | ||||
@@ -37,3 +39,26 @@ uint64_t util_timespec_diff(const struct timespec *past, | |||||
int64_t nsdiff = future->tv_nsec - past->tv_nsec; | int64_t nsdiff = future->tv_nsec - past->tv_nsec; | ||||
return sdiff * 1000 + (nsdiff / 1000000); | return sdiff * 1000 + (nsdiff / 1000000); | ||||
} | } | ||||
uint64_t util_iso2unix(const char *isotime) | |||||
{ | |||||
struct tm tm = {0}; | |||||
char *ms = strptime(isotime, "%Y-%m-%d", &tm); | |||||
if (!ms || (*ms != '\0' && *ms != ' ' && *ms != 'T')) | |||||
return 0; | |||||
if (*ms == '\0') | |||||
ms = "T00:00:00"; | |||||
ms = strptime(ms + 1, "%H:%M", &tm); | |||||
if (!ms || (*ms != '\0' && *ms != ':')) | |||||
return 0; | |||||
if (*ms == '\0') | |||||
ms = ":00"; | |||||
ms = strptime(ms + 1, "%S", &tm); | |||||
if (!ms) | |||||
return 0; | |||||
return mktime(&tm); | |||||
} |
@@ -42,4 +42,10 @@ char *util_basename(const char *fullpath); | |||||
uint64_t util_timespec_diff(const struct timespec *past, | uint64_t util_timespec_diff(const struct timespec *past, | ||||
const struct timespec *future); | const struct timespec *future); | ||||
/* | |||||
* Convert a date and optionally time string into unix time | |||||
* Returns 0 on error | |||||
*/ | |||||
uint64_t util_iso2unix(const char *isotime); | |||||
#endif /* _UTIL_H */ | #endif /* _UTIL_H */ |