diff --git a/src/api.c b/src/api.c index ace3981..a4d03ae 100644 --- a/src/api.c +++ b/src/api.c @@ -677,18 +677,12 @@ static enum error api_cmd_base_errorc(long code, char buffer[API_BUFSIZE]) * 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, ...) +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; - va_list ap; 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); api_g_retry_count = 0; @@ -754,6 +748,18 @@ end: pthread_mutex_unlock(&api_work_mx); 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) { @@ -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 mylist_state ml_state, bool watched, struct api_result *res) + struct api_mylistadd_opts *opts, struct api_result *res) { char buffer[API_BUFSIZE]; char hash_str[ED2K_HASH_SIZE * 2 + 1]; enum error err = NOERR; + int send_len; util_byte2hex(hash, ED2K_HASH_SIZE, false, hash_str); /* 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) return err; @@ -939,4 +956,27 @@ enum error api_cmd_mylistadd(int64_t size, const uint8_t *hash, 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 diff --git a/src/api.h b/src/api.h index 101a477..0519893 100644 --- a/src/api.h +++ b/src/api.h @@ -203,6 +203,17 @@ enum file_state { 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 { 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 struct api_result { @@ -241,6 +255,7 @@ struct api_result { struct api_uptime_result uptime; e(mylistadd); e(encrypt); + e(mylistmod); }; }; #undef e @@ -251,6 +266,8 @@ void api_free(); enum error api_cmd_version(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 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 */ diff --git a/src/cmd.c b/src/cmd.c index 4f6a119..c5fd9d0 100644 --- a/src/cmd.c +++ b/src/cmd.c @@ -23,6 +23,7 @@ static const struct cmd_entry ents[] = { { .arg_name = "uptime", .fn = cmd_server_uptime, .need_auth = true }, { .arg_name = "ed2k", .fn = cmd_ed2k, }, { .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); diff --git a/src/cmd.h b/src/cmd.h index 2229039..57442dc 100644 --- a/src/cmd.h +++ b/src/cmd.h @@ -35,4 +35,9 @@ enum error cmd_server_uptime(void *); */ enum error cmd_prog_version(void *); +/* + * Modifies a mylist entry + */ +enum error cmd_modify(void *data); + #endif /* _CMD_H */ diff --git a/src/cmd_add.c b/src/cmd_add.c index b6c4b2d..ac73af4 100644 --- a/src/cmd_add.c +++ b/src/cmd_add.c @@ -12,11 +12,6 @@ #include "cache.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, void *data) { @@ -43,9 +38,9 @@ enum error cmd_add_apisend(const char *path, const uint8_t *hash, const struct stat *st, void *data) { 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) 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) { - struct add_opts add_opts = {0}; + struct api_mylistadd_opts mopt = {0}; struct ed2k_util_opts ed2k_opts = { .pre_hash_fn = cmd_add_cachecheck, .post_hash_fn = cmd_add_apisend, - .data = &add_opts, + .data = &mopt, }; bool *watched; + const char **wdate_str; enum error err = NOERR; int fcount; @@ -99,10 +95,23 @@ enum error cmd_add(void *data) 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++) { err = ed2k_util_iterpath(config_get_nonopt(i), &ed2k_opts); diff --git a/src/cmd_modify.c b/src/cmd_modify.c new file mode 100644 index 0000000..c89a040 --- /dev/null +++ b/src/cmd_modify.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include + +#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; +} + diff --git a/src/config.c b/src/config.c index beed4c0..19882d6 100644 --- a/src/config.c +++ b/src/config.c @@ -110,6 +110,10 @@ static struct conf_entry options[] = { .set_func = config_set_bool, .in_args = true, .in_file = 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 ###*/ { .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, .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, .type = OTYPE_B, .handle_order = 1, .value_is_set = true },*/ diff --git a/src/util.c b/src/util.c index b02e51f..dd4a1ae 100644 --- a/src/util.c +++ b/src/util.c @@ -1,5 +1,7 @@ +#define _XOPEN_SOURCE #include #include +#include #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; 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); +} diff --git a/src/util.h b/src/util.h index f17e578..c0a926f 100644 --- a/src/util.h +++ b/src/util.h @@ -42,4 +42,10 @@ char *util_basename(const char *fullpath); uint64_t util_timespec_diff(const struct timespec *past, 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 */