diff --git a/man/Makefile.am b/man/Makefile.am index ffa94f9cc1a269ad0b89716faee4669bb59730ea..4699b3a78b65a5dbcd83d5e2969ab2304644b8f8 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -1,4 +1,4 @@ -lkt_manpages = lektor.man lektord.man lkt.man lkt.old.man +lkt_manpages = lektor.man lektord.man lkt.man notrans_dist_man1_MANS = $(lkt_manpages) MAN = $(abs_top_srcdir)/scripts/manpage.bash CLEANFILES = $(lkt_manpages) diff --git a/man/Makefile.in b/man/Makefile.in index 9f4e3af0fff28732aacddc411a35f3b25ac6f91d..e464bfa443983992fe300025f81a5378b2bf82e4 100644 --- a/man/Makefile.in +++ b/man/Makefile.in @@ -286,7 +286,7 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -lkt_manpages = lektor.man lektord.man lkt.man lkt.old.man +lkt_manpages = lektor.man lektord.man lkt.man notrans_dist_man1_MANS = $(lkt_manpages) CLEANFILES = $(lkt_manpages) all: all-am diff --git a/man/footer b/man/footer index 8301ba8d8697ee6da0f3d33069cc915a0216a4ca..3fd0a054894a397ddcfe73161fb159a9a061fa34 100644 --- a/man/footer +++ b/man/footer @@ -12,6 +12,5 @@ \fIlektor\fP(1), \fIlektord\fP(1), \fIlkt\fP(1), -\fIlkt.old\fP(1), \fImpc\fP(1), \fImpd\fP(1) diff --git a/man/lektor.template b/man/lektor.template index 49766112f26a0cae216017128fea6bc69c6cb969..b682cae63ee09fe0509fbfc8c11de0c9bca20d9f 100644 --- a/man/lektor.template +++ b/man/lektor.template @@ -15,8 +15,6 @@ You may be interested in other related programs like: \fIlektord\fP The lektor daemon .TP \fIlkt\fP A standard client for lektord -.TP -\fIlkt.old\fP A standard client for lektord, the old and deprecated version .PD .SH "DESCRIPTION" diff --git a/man/lkt.old.template b/man/lkt.old.template deleted file mode 100644 index 8c4837fa4bfd82de4afdbfd0ed5b5551f858123d..0000000000000000000000000000000000000000 --- a/man/lkt.old.template +++ /dev/null @@ -1,274 +0,0 @@ -.\" vim: ft=groff -.TH "LKT.OLD" "1" "___DATE___" "LEKTOR MK 7" -.SH "NAME" - -lkt.old \- the old lektor command line client, kept for some back-compatibility issues - -.PP -\fB/!\\ Deprecated /!\\\fP - -.SH "OVERVIEW" -\fBlkt.old\fP is the old \fBlektord\fP client, much like \fBmpc\fP but with -more functionnalities like \fIplaylists\fP and \fIstickers\fP management. -.PP -Because \fBlkt.old\fP is replaced by \fBlkt\fP, its usage is deprecated in -favor of \fBlkt\fP. The differences are the following: -.IP \[bu] 2 -Some types in queries are optional. Thus the type is infered from the regex -part and it means that some \fIqueries\fP are no longer possible. -.PP -Commands can be used with the minimal name that permit them to be -distinguished from others commands. Thus, it is possible to use the -string \fIadm\fP as an alias for \fIadmin\fP. This is like cisco switch -command line interface. -.PP - -.SH "COMMANDS" -Here are the \fBlkt.old\fP commands: - -.PP -\fIBASE-COMMANDS\fP -.PP -.PD 0 -.TP -.PD -\fBcurrent\fP -Prints informations about the currently playing kara. Can be used to -display the current kara in a status bar like \fBxmobar\fP or in the -\fBi3 panel\fP -.TP -\fBplay\fP [index] -Toggle play/pause state. If the playback is stopped, start at a possibly -specified index -.TP -\fBnext\fP -Play next kara in the queue -.TP -\fBprevious\fP -Play the previous kara in the queue -.TP -\fBshuffle\fP -Shuffle the queue. If the state was stoppped, play from the first kara -in the queue. If lektor was already playing a kara, it will play it -from the begening. The current kara will be placed in first position -in the queue. -.TP -\fBstatus\fP -Prints information about the state of lektor and the currently playing kara -.TP -\fBstop\fP -Stop the playback and reading the queue, the state is now \fIstopped\fP. -.PP -\fIPLAYLIST-COMMANDS\fP -.PP -.PD 0 -.TP -.PD -\fBplt create\fP <plt-name> -Creates a playlist, do nothing if it was already present -.TP -\fBplt destroy\fP <plt-name> -Delete a playlist with all its content, do nothing if the playlist didn't exists -.TP -\fBplt delete\fP <plt-name> <query> -Deletes karas from a playlist with a valid \fIquery\fP -.TP -\fBplt add\fP <plt-name> <query> -Adds karas to a playlist with a valid \fIquery\fP -.TP -\fBplt list\fP <plt-name> -List the content of the playlist named <plt-name> -.TP -\fBplt list\fP -List all the available playlists -.PP - -\fIQUEUE-COMMANDS\fP -.PP -.PD 0 -.TP -.PD -\fBqueue\fP [count] -Prints the names and ids of the next karas in the queue -.TP -\fBqueue pos\fP <pos | from:to> -Prints the names and ids of karas in the queue. Karas can be designated by -their position or with a range -.TP -\fBqueue pop\fP -Delete the currently playing kara from the queue and pass to the next one. -This can work only if the currently playong kara is not the last -.TP -\fBqueue add\fP <query> -Add karas to the queue at the end of it with a valid query -.TP -\fBqueue insert\fP <query> -Add karas to the queue just after the currently playing kara -.TP -\fBqueue seek\fP <id> -Goto to the kara with the specified id in the queue -.TP -\fBqueue delete\fP <id> -Delete karas from the playlist with their id. You can't delete the currently -playing kara, for that use the \fBpop\fP queue command -.TP -\fBqueue clear\fP -Clear the queue and set the state to \fIstopped\fP -.TP -\fBqueue crop\fP -Crop the queue, delete every kara from it appart from the currently -playing one -.TP -\fBqueue replace\fP <plt-name> -Replace the queue with the content of a playlist. Keep the playling state -.PP - -\fISEARCH-COMMANDS\fP -.PP -.PD 0 -.TP -.PD -\fBsearch database\fP <query> -Search and prints the kara that correspond to the query in the database -.TP -\fBsearch plt\fP <plt-name> <query> -Search, prints and add to an existing playlist the karas that match -the query -.TP -\fBsearch plt\fP <plt-name> -List the content of the playlist named <plt-name> -.TP -\fBsearch plt\fP -List all the available playlists -.TP -\fBsearch count\fP <query> -Search and prints the number of karas that match the query -.TP -\fBsearch get\fP <id> -Get informations about a specific id -.TP -\fBsearch queue\fP <query> -Search in the queue and prints the karas that match the query -.PP - -\fISTICKERS-COMMANDS\fP -.PP -.PD 0 -.TP -.PD -\fBsticker create\fP <name> -Create a sticker that can be used to tag \fIkara\fP and \fIplt\fP objects -.TP -\fBsticker get\fP <type> <uri> [ <name> [ <op> <value> ] ] -List the stickers of an object \fIuri\fP. The object \fItype\fP can be -\fIkara\fP or \fIplt\fP - -A condition can be defined on the value of the sticker with an operator -\fIop\fP and an integer value \fIvalue\fP. Supported operators are \fIl\fP -for 'less than', \fIe\fP for 'equal to' and \fIg\fP for 'greater than'. -Operations are not strict -.TP -\fBsticker set\fP <type> <uri> <name> <value> -Set the value of a sticker \fIname\fP to \fIvalue\fP for the object with the -id \fIuri\fP -.TP -\fBsticker delete\fP <type> <uri> [name] -Delete all the stickers or only one (specified by \fIname\fP) of the object -with the id \fIuri\fP -.PP - -\fIADMIN-COMMANDS\fP -.PP -.PD 0 -.TP -.PD -\fBadmin ping\fP -Pings the lektord daemon, prints \fIOK\fP only if the ping succeeded -.TP -\fBadmin kill\fP -Kill the lektord daemon -.TP -\fBadmin restart\fP -Try to restart the lektord daemon -.TP -\fBadmin rescan\fP -Rescan karas from the filesystem. New karas that are not in the database -will be added to it. Don't synchronize from the repo -.TP -\fBadmin populate\fP -Force a rescan (without taking into account the timestamp). Can be used -to bootstrap the database from a filesystem -.TP -\fBadmin update\fP -Update the base from the \fIKurisu\fP repo. Don't scan for new files in -the filesystem -.TP -\fBadmin config\fP -Prints to \fIstdout\fP the default configuration file -.PP - -.SH "OPTIONS" -Options can be passed to \fBlkt.old\fP before specifying the command in a -\fIoption=value\fP format. This is done this way to allow one to make an alias -of the \fBlkt.old\fP command. -.PP -The possible options are the following: -.PP -.PD 0 -.TP -.PD -\fBhost\fP -The hostname or the IP of the machine where the \fBlektord\fP daemon -is running -.TP -\fBport\fP -The port on which the \fBlektord\fP daemon is listening -.TP -\fBpwd\fP -The password to use for commands that require authentification. This is the -case of most of the \fIadmin\fP commands -.PP - -.SH "QUERIES" -Queries are a way of listing karas in the database. They are composed of a -type and the next of the line is the SQL regex that the kara must verify. -In SQL regexes, the wildcard is the "%" character and the jocker the -character "_". Queries are case insensitive. -.PP -Valid types for a query are the following: \fIid\fP, \fIlang\fP, \fItype\fP, -\fIcategory\fP, \fIauthor\fP, \fIquery\fP and \fIplaylist\fP. -.PP -For the type \fItype\fP, the valid values are the following: \fIOP\fP, -\fIED\fP, \fIIS\fP, \fIAMV\fP, \fIMV\fP, \fIPV\fP and \fILIVE\fP. -.PP -For the type \fIlang\fP, the valid values are the following: \fIjp\fP, -\fIfr\fP, \fIsp\fP, \fIen\fP, \fIlatin\fP, \fIit\fP, \fIru\fP, \fImulti\fP -and \fIundefined\fP. -.PP -For the \fIcategory\fP type, the valid values are the following: -\fIvo\fP, \fIva\fP, \fIcdg\fP, \fIamv\fP, \fIvocaloid\fP and \fIautres\fP. -.PP -Here are some examples of queries: -.PP -.PD 0 -.TP -.PD -\fBtype OP\fP -Select karas that are openings -.TP -\fBauthor kubat\fP -Select karas where the author is "kubat" -.PP - -.SH "EXAMPLES" -Valid invocations of the \fBlkt.old\fP command are the following: -.PP -.PD 0 -.TP -.PD -\fBlkt.old host=sakura port=6601 pwd=toto admin restart\fP -Restart the lektord daemon on the \fIsakura\fP PC. This daemon is listening on -the port \fI6601\fP and the password of the admin user is \fItoto\fP -.TP -\fBlkt.old q a author krocoh\fP -Add kara that Krocoh has done to the queue diff --git a/man/lkt.template b/man/lkt.template index b11343d4c2de761c01472b593c80325f15dadd49..3c3073f304c40b16837344931cf6ebcc26134035 100644 --- a/man/lkt.template +++ b/man/lkt.template @@ -196,6 +196,10 @@ to bootstrap the database from a filesystem Update the base from the \fIKurisu\fP repo. Don't scan for new files in the filesystem .TP +\fBadmin import\fP +Import favorites from the \fIKurisu\fP repo. Favorites will create playlists on +the lektor side begening with the @ character +.TP \fBadmin config\fP Prints to \fIstdout\fP the default configuration file .PP diff --git a/src/Makefile.am b/src/Makefile.am index eac0e4cbee317428865ae8093a201f975783beb1..b95770d7d3c592a42eadd389e0c620708c12b9d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -84,10 +84,9 @@ EXTRA_DIST = database/disk.sql database/memory.sql ## MAIN FILES ## ################ -bin_PROGRAMS = lektord lkt.old lkt +bin_PROGRAMS = lektord lkt ## The lkt client -lkt_old_SOURCES = main/lkt-old.c base/cmd.c base/common.c lkt_SOURCES = main/lkt.c base/cmd.c base/common.c ## The lektord server diff --git a/src/Makefile.in b/src/Makefile.in index 0c7d8c290652282b4d1e4483e64548e4662b3e77..d824d34b88da889e9d0336697d3320b003268696 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -99,7 +99,7 @@ host_triplet = @host@ # TODO pour le Kubat du futur: c'est pas beau, trouver un truc pour que ça se fasse tout seul @LKT_STATIC_MODULE_TRUE@am__append_8 = module/thread.c -bin_PROGRAMS = lektord$(EXEEXT) lkt.old$(EXEEXT) lkt$(EXEEXT) +bin_PROGRAMS = lektord$(EXEEXT) lkt$(EXEEXT) subdir = src ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/config/m4/libtool.m4 \ @@ -212,10 +212,6 @@ am_lkt_OBJECTS = main/lkt.$(OBJEXT) base/cmd.$(OBJEXT) \ base/common.$(OBJEXT) lkt_OBJECTS = $(am_lkt_OBJECTS) lkt_LDADD = $(LDADD) -am_lkt_old_OBJECTS = main/lkt-old.$(OBJEXT) base/cmd.$(OBJEXT) \ - base/common.$(OBJEXT) -lkt_old_OBJECTS = $(am_lkt_old_OBJECTS) -lkt_old_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false @@ -249,8 +245,7 @@ am__depfiles_remade = base/$(DEPDIR)/cmd.Po base/$(DEPDIR)/common.Po \ database/$(DEPDIR)/liblektor_la-queue.Plo \ database/$(DEPDIR)/liblektor_la-stickers.Plo \ database/$(DEPDIR)/liblektor_la-update.Plo \ - database/$(DEPDIR)/liblektor_la-user.Plo \ - main/$(DEPDIR)/lkt-old.Po main/$(DEPDIR)/lkt.Po \ + database/$(DEPDIR)/liblektor_la-user.Plo main/$(DEPDIR)/lkt.Po \ main/$(DEPDIR)/server.Po mkv/$(DEPDIR)/liblektor_la-mkv.Plo \ mkv/$(DEPDIR)/liblektor_la-utils.Plo \ mkv/$(DEPDIR)/liblektor_la-write.Plo \ @@ -282,11 +277,10 @@ am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(liblektor_la_SOURCES) $(liblktmodrepo_la_SOURCES) \ - $(liblktmodsdl_la_SOURCES) $(lektord_SOURCES) $(lkt_SOURCES) \ - $(lkt_old_SOURCES) + $(liblktmodsdl_la_SOURCES) $(lektord_SOURCES) $(lkt_SOURCES) DIST_SOURCES = $(am__liblektor_la_SOURCES_DIST) \ $(liblktmodrepo_la_SOURCES) $(liblktmodsdl_la_SOURCES) \ - $(lektord_SOURCES) $(lkt_SOURCES) $(lkt_old_SOURCES) + $(lektord_SOURCES) $(lkt_SOURCES) am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ @@ -483,7 +477,6 @@ liblektor_la_LDFLAGS = -avoid-version -pthread -lsqlite3 \ @LKT_STATIC_MODULE_TRUE@liblektor_la_LIBADD = liblktmodsdl.la liblktmodrepo.la CLEANFILES = database/disk.c database/memory.c EXTRA_DIST = database/disk.sql database/memory.sql -lkt_old_SOURCES = main/lkt-old.c base/cmd.c base/common.c lkt_SOURCES = main/lkt.c base/cmd.c base/common.c lektord_SOURCES = main/server.c lektord_LDADD = liblektor.la @@ -751,12 +744,6 @@ base/common.$(OBJEXT): base/$(am__dirstamp) \ lkt$(EXEEXT): $(lkt_OBJECTS) $(lkt_DEPENDENCIES) $(EXTRA_lkt_DEPENDENCIES) @rm -f lkt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(lkt_OBJECTS) $(lkt_LDADD) $(LIBS) -main/lkt-old.$(OBJEXT): main/$(am__dirstamp) \ - main/$(DEPDIR)/$(am__dirstamp) - -lkt.old$(EXEEXT): $(lkt_old_OBJECTS) $(lkt_old_DEPENDENCIES) $(EXTRA_lkt_old_DEPENDENCIES) - @rm -f lkt.old$(EXEEXT) - $(AM_V_CCLD)$(LINK) $(lkt_old_OBJECTS) $(lkt_old_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) @@ -795,7 +782,6 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@database/$(DEPDIR)/liblektor_la-stickers.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@database/$(DEPDIR)/liblektor_la-update.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@database/$(DEPDIR)/liblektor_la-user.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/lkt-old.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/lkt.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@main/$(DEPDIR)/server.Po@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@mkv/$(DEPDIR)/liblektor_la-mkv.Plo@am__quote@ # am--include-marker @@ -1217,7 +1203,6 @@ distclean: distclean-am -rm -f database/$(DEPDIR)/liblektor_la-stickers.Plo -rm -f database/$(DEPDIR)/liblektor_la-update.Plo -rm -f database/$(DEPDIR)/liblektor_la-user.Plo - -rm -f main/$(DEPDIR)/lkt-old.Po -rm -f main/$(DEPDIR)/lkt.Po -rm -f main/$(DEPDIR)/server.Po -rm -f mkv/$(DEPDIR)/liblektor_la-mkv.Plo @@ -1296,7 +1281,6 @@ maintainer-clean: maintainer-clean-am -rm -f database/$(DEPDIR)/liblektor_la-stickers.Plo -rm -f database/$(DEPDIR)/liblektor_la-update.Plo -rm -f database/$(DEPDIR)/liblektor_la-user.Plo - -rm -f main/$(DEPDIR)/lkt-old.Po -rm -f main/$(DEPDIR)/lkt.Po -rm -f main/$(DEPDIR)/server.Po -rm -f mkv/$(DEPDIR)/liblektor_la-mkv.Plo diff --git a/src/main/lkt-old.c b/src/main/lkt-old.c deleted file mode 100644 index f6c0987ca2c0b8398f4edb2abee19296cb914196..0000000000000000000000000000000000000000 --- a/src/main/lkt-old.c +++ /dev/null @@ -1,1154 +0,0 @@ -#define _POSIX_C_SOURCE 200809L - -#include <lektor/common.h> -#include <lektor/net.h> -#include <lektor/cmd.h> -#include <lektor/config.h> - -#include <arpa/inet.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <errno.h> -#include <fcntl.h> -#include <netdb.h> -#include <stdint.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <strings.h> -#include <unistd.h> -#include <signal.h> -#include <locale.h> -#include <stdnoreturn.h> -#include <stdbool.h> -#include <stdarg.h> -#include <limits.h> - -#define LKT_KEY_VALUE_SEP ": \n\t\0" -#define fail_if(cond, msg) { if (cond) { LOG_ERROR("LKT", "%s", msg); exit(EXIT_FAILURE); } } -#define fail(msg) { LOG_ERROR("LKT", "%s", msg); exit(EXIT_FAILURE); } - -#define exit_with_status(sock, buff) { \ - read_socket(sock, buff, 2); \ - fail_if(buff[0] != 'O' && buff[1] != 'K', "ACK"); \ - exit(EXIT_SUCCESS); \ -} - -/* Type definition. */ - -typedef struct { - const char *host; /* Serveur host, may be resolved. */ - const char *port; /* Serveur port. */ - const char *pwd; /* The password for the user. */ - const char **argv; /* Pointer to the argv from the main function. */ - int argc; /* Argument count of the args. */ -} args_t; - -/* Global variables. */ - -static const char *host; -static const char *port; -static const char *password; -static const char *LKT_QUEUE_DEFAULT[] = { "10" }; - -/* Communication functions and fonction that interact with lektor stuff. */ - -static int -lkt_valid_type(const char *type) -{ - return (STR_MATCH(type, "query") || - STR_MATCH(type, "category") || - STR_MATCH(type, "author") || - STR_MATCH(type, "lang") || - STR_MATCH(type, "id") || - STR_MATCH(type, "type") || - STR_MATCH(type, "playlist")); -} - -static int -read_socket(FILE *sock, char *buff, size_t max_len) -{ - size_t i, len; - for (i = 0; i < max_len; ++i) { - len = fread(buff + i, sizeof(char), 1, sock); - if (buff[i] == '\n' || len != 1) - break; - } - fail_if(len == 0, "Connexion error"); - return i; -} - -static FILE * -create_socket(const char *host, const char *port) -{ - FILE *socket_desc; - struct addrinfo hints, *found; - socklen_t sock_len; - struct sockaddr sock; - - memset(&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = 0; - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - getaddrinfo(host, port, &hints, &found); // <---- Another assert yeeted because it makes php panic - - sock = *found->ai_addr; - sock_len = found->ai_addrlen; - freeaddrinfo(found); - - int cx = socket(AF_INET, SOCK_STREAM, 0); - - if (cx <= 0 || connect(cx, &sock, sock_len)) - exit(EXIT_FAILURE); - - socket_desc = fdopen(cx, "r+"); - fail_if(!socket_desc, "Failed to connect to lektord"); - return socket_desc; -} - -static FILE * -lkt_connect(void) -{ - char buff[LKT_MESSAGE_MAX]; - FILE *sock = create_socket(host, port); - read_socket(sock, buff, LKT_MESSAGE_MAX); - return sock; -} - -static void -write_socket(FILE *sock, const char *format, ...) -{ - int size; - char buff[LKT_MESSAGE_MAX]; - va_list ap; - - va_start(ap, format); - size = vsnprintf(buff, LKT_MESSAGE_MAX - 1, format, ap); - buff[LKT_MESSAGE_MAX - 1] = 0; - - if (size < 0) - fail("Connexion error"); - - if (fwrite(buff, sizeof(char), size, sock) < (unsigned int) size) - fail("Connexion error"); - - va_end(ap); -} - -noreturn static inline void -lkt_send_and_exit(const char *buffer, size_t len) -{ - write_socket(lkt_connect(), buffer, len); - exit(EXIT_SUCCESS); -} - -static char * -lkt_skip_key(char *buffer) -{ - size_t len = strcspn(buffer, LKT_KEY_VALUE_SEP); - char *ret = &buffer[len + 1]; - len = strspn(ret, ": "); - return ret + len; -} - -static inline void -send_cmd_with_uri(FILE *sock, char *cmd, int argc, const char **argv) -{ - int i; - char buf[LKT_MESSAGE_MAX] = {0}; - for (i = 1; i < argc - 1; ++i) { - strncat(buf, argv[i], LKT_MESSAGE_MAX - 1); - strncat(buf, " ", LKT_MESSAGE_MAX - 1); - } - strncat(buf, argv[i], LKT_MESSAGE_MAX - 1); - strncat(buf, "\n", LKT_MESSAGE_MAX - 1); - write_socket(sock, "%s %s://%s", cmd, argv[0], buf); -} - -/* Functions implementing options. */ - -#define just_send_one_arg(func, cmd) \ -noreturn void func (struct cmd_args *args) { \ - fail_if(args->argc != 1, "Invalid argument"); \ - FILE *sock = lkt_connect(); \ - char buff[2]; \ - write_socket(sock, cmd " %s\n", args->argv[0]); \ - exit_with_status(sock, buff); \ -} -just_send_one_arg(stickers_create__, "sticker __create") -just_send_one_arg(stickers_destroy__, "sticker __destroy") -just_send_one_arg(plt_destroy__, "rm") -just_send_one_arg(plt_create__, "playlistadd") -just_send_one_arg(queue_dump__, "__dump") -#undef just_send_one_arg - -#define just_send(func, msg) /* Just send a simple string functions */ \ - noreturn void func (struct cmd_args *args) { \ - fail_if(args->argc, "This command takes no arguments"); \ - lkt_send_and_exit(msg, sizeof(msg)); \ - } -just_send(queue_clear__, "clear\n") -just_send(queue_crop__, "crop\n") -just_send(next__, "next\n") -just_send(prev__, "previous\n") -just_send(stop__, "stop\n") -just_send(shuffle__, "shuffle\nplay\n") -#undef just_send - -noreturn void -simple_send_with_password__(const char *cmd) -{ - if (!password) - fail("Password not provided"); - FILE *sock = lkt_connect(); - write_socket(sock, "command_list_begin\n"); - write_socket(sock, "password %s\n", password); - write_socket(sock, "%s\n", cmd); - write_socket(sock, "command_list_end\n"); - exit(EXIT_SUCCESS); -} - -noreturn void -restart__(struct cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the previous command takes no arguments"); - simple_send_with_password__("__restart"); -} - -noreturn void -kill__(struct cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the previous command takes no arguments"); - simple_send_with_password__("kill"); -} - -noreturn void -rescan_or_update__(struct cmd_args *args, const char *cmd) -{ - if (!password) - fail("Password not provided"); - FILE *sock = lkt_connect(); - char buff[LKT_MESSAGE_MAX]; - int i; - - /* All the db */ - if (args->argc == 0) { - write_socket(sock, "command_list_begin\n"); - write_socket(sock, "password %s\n", password); - write_socket(sock, "%s\n", cmd); - write_socket(sock, "command_list_end\n"); - } - - /* With a query */ - else { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - for (i = 0; i < args->argc; ++i) - strncat(buff, args->argv[i], LKT_MESSAGE_MAX - 1); - write_socket(sock, "command_list_begin\n"); - write_socket(sock, "password %s\n", password); - write_socket(sock, "%s %s\n", cmd, buff); - write_socket(sock, "command_list_end\n"); - } - - exit(EXIT_SUCCESS); -} - -noreturn void -rescan__(struct cmd_args *args) -{ - rescan_or_update__(args, "rescan"); -} - -noreturn void -update__(struct cmd_args *args) -{ - rescan_or_update__(args, "update"); -} - -noreturn void -populate__(struct cmd_args *args) -{ - rescan_or_update__(args, "__rescan"); -} - -noreturn void -queue_replace__(struct cmd_args *args) -{ - if (args->argc != 1) - fail("Invalid argument"); - bool play = false; - char buff[LKT_MESSAGE_MAX]; - FILE *sock = lkt_connect(); - - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); - - if (STR_NMATCH(buff, "state", len)) { - char *it = lkt_skip_key(buff); - play = STR_NMATCH(it, "play", 4); - break; - } - - if (STR_NMATCH(buff, "OK", 2)) - break; - else if (STR_NMATCH(buff, "ACK", 3)) - fail("ACK"); - } - - fclose(sock); - sock = lkt_connect(); - write_socket(sock, "command_list_begin\n"); - write_socket(sock, "clear\n"); - write_socket(sock, "add playlist://%s\n", args->argv[0]); - if (play) - write_socket(sock, "play\n"); - write_socket(sock, "command_list_end\n"); - exit_with_status(sock, buff); -} - -noreturn void -config__(struct cmd_args *args) -{ - int ret = EXIT_SUCCESS; - if (args->argc == 0) - fwrite(lkt_default_config_file, sizeof(char), - strlen(lkt_default_config_file), stdout); - exit(ret); -} - -noreturn void -play__(struct cmd_args *args) -{ - if (args->argc > 1) - fail("Invalid argument"); - - int pos = 0; - if (args->argc != 0) - pos = atoi(args->argv[0]); - - static const char status__[] = "status\n"; - static const char cmd_play__[] = "play\n"; - static const char cmd_play_from__[] = "play %d\n"; - static const char cmd_pause__[] = "pause\n"; - - char buff[LKT_MESSAGE_MAX]; - FILE *sock = lkt_connect(); - write_socket(sock, status__); - - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); - - if (STR_NMATCH(buff, "state", len)) { - fclose(sock); - - if (STR_NMATCH(lkt_skip_key(buff), "stop", 4)) { - if (!pos) - lkt_send_and_exit(cmd_play__, sizeof(cmd_play__)); /* In bytes. */ - else { - write_socket(lkt_connect(), cmd_play_from__, pos); - exit(EXIT_SUCCESS); - } - } - - else - lkt_send_and_exit(cmd_pause__, sizeof(cmd_pause__)); /* In bytes. */ - - exit(EXIT_FAILURE); - } - } -} - -noreturn void -ping__(struct cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the ping command takes no arguments"); - char buff[6] = {0}; - FILE *sock = lkt_connect(); - write_socket(sock, "ping\n"); - read_socket(sock, buff, 6 * sizeof(char)); - if (!STR_NMATCH(buff, "OK", 2)) - fail("ACK"); - exit(write(1, "OK\n", sizeof("OK\n")) == 0); -} - -noreturn void -current__(struct cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the current command takes no arguments"); - - static const char current_song__[] = "currentsong\n"; - char buff[LKT_MESSAGE_MAX]; - - char *mem = NULL; - FILE *sock = lkt_connect(); - - write_socket(sock, current_song__); - assert(mem = calloc(6 * LKT_MESSAGE_MAX, sizeof(char))); - assert(memset(mem, 0, 6 * LKT_MESSAGE_MAX * sizeof(char))); - - char *const title = &mem[0]; - char *const author = &mem[LKT_MESSAGE_MAX]; - char *const source = &mem[2 * LKT_MESSAGE_MAX]; - char *const type = &mem[3 * LKT_MESSAGE_MAX]; - char *const category = &mem[4 * LKT_MESSAGE_MAX]; - char *const language = &mem[5 * LKT_MESSAGE_MAX]; - - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - - const size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); - char *value = lkt_skip_key(buff); - const size_t value_size = strcspn(value, "\n\0") * sizeof(char); - - if (STR_NMATCH("title", buff, len)) - assert(memcpy(title, value, value_size)); - - if (STR_NMATCH("author", buff, len)) - assert(memcpy(author, value, value_size)); - - if (STR_NMATCH("source", buff, len)) - assert(memcpy(source, value, value_size)); - - if (STR_NMATCH("type", buff, len)) - assert(memcpy(type, value, value_size)); - - if (STR_NMATCH("language", buff, len)) - assert(memcpy(language, value, value_size)); - - if (STR_NMATCH("category", buff, len)) - assert(memcpy(category, value, value_size)); - - /* At this point every key has been parsed. */ - if (STR_NMATCH(buff, "OK", 2)) - goto ok; - else if (STR_NMATCH(buff, "ACK", 3)) - exit(EXIT_FAILURE); - } - -ok: - if (language[0]) - printf("%s - %s / %s - %s - %s [ %s ]\n", - category, language, source, type, title, author); - else - printf("%s / %s - %s - %s [ %s ]\n", - category, source, type, title, author); - - exit(EXIT_SUCCESS); -} - -noreturn void -queue_pop__(struct cmd_args *args) -{ - fail_if(args->argc, "Invalid argument"); - int songid = 0; - char buff[LKT_MESSAGE_MAX]; - FILE *sock = lkt_connect(); - - /* Get lektor's status. */ - write_socket(sock, "status\n"); - -#define assign_int(str, var) if (STR_NMATCH(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; } - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); - assign_int("songid", songid) - - /* At this point every key has been parsed. */ - if (STR_NMATCH(buff, "OK", 2)) - break; - else if (STR_NMATCH(buff, "ACK", 3)) - exit(EXIT_FAILURE); - } -#undef assign_int - - fclose(sock); - sock = lkt_connect(); - if (!songid) - exit(EXIT_FAILURE); - write_socket(sock, "next\ndeleteid %d\n", songid); - exit_with_status(sock, buff); -} - -noreturn void -status__(struct cmd_args *args) -{ - if (args->argc != 0) - fail("Invalid argument, the status command takes no arguments"); - - static const char *const status_str__ = "status\n"; - static const char *const stats_str__ = "stats\n"; - - char buff[LKT_MESSAGE_MAX]; - char flags[24]; - - bool play = false, stopped = true, is_updating = false; - int time_pos = 0, time_duration = 0, song_index = 0, plt_len = 0, ret = EXIT_FAILURE, it = 0; - size_t len; - time_t update_ts = 0; - - memset(flags, 0, 24 * sizeof(char)); - FILE *sock = lkt_connect(); - -#define assign_flag(str, f) if (STR_NMATCH(buff, str, len) && (atoi(lkt_skip_key(buff)) == 1)) { flags[it++] = f; continue; } -#define assign_int(str, var) if (STR_NMATCH(buff, str, len)) { var = (strtoll(lkt_skip_key(buff), NULL, 0)); continue; } -#define check_end() \ - if (STR_NMATCH(buff, "OK", 2)) break; \ - else if (STR_NMATCH(buff, "ACK", 3)) goto error; - - /* Get lektor's status */ - write_socket(sock, status_str__); - for (;;) { - len = read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - buff[len] = '\0'; - len = strcspn(buff, LKT_KEY_VALUE_SEP); - - if (STR_NMATCH(buff, "state", len)) { - char *it = lkt_skip_key(buff); - play = STR_NMATCH(it, "play", 4); - stopped = STR_NMATCH(it, "stop", 4); - continue; - } - - assign_flag("random", 'r') - assign_flag("repeat", 'l') - assign_flag("single", 's') - assign_flag("consume", 'c') - - assign_int("elapsed", time_pos) - assign_int("duration", time_duration) - assign_int("song", song_index) - assign_int("playlistlength", plt_len) - - check_end() - } - - /* Get lektor's stats */ - write_socket(sock, stats_str__); - for (;;) { - len = read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - buff[len] = '\0'; - len = strcspn(buff, LKT_KEY_VALUE_SEP); - - assign_int("__is_updating", is_updating) - assign_int("db_update", update_ts) - - check_end() - } - - /* End of communication */ - fclose(sock); - -#undef assign_flag -#undef assign_int -#undef check_end - - struct tm *p_tm = localtime(&update_ts); - len = strftime(buff, LKT_MESSAGE_MAX - 1, "%F %H:%M:%S", p_tm); - buff[len] = '\0'; - - int pla_m = time_pos / 60; - char pla_s = time_pos % 60; - int dur_m = time_duration / 60; - char dur_s = time_duration % 60; - - printf("Lektor: %s\n" - "Queue: #%d/%d\n" - "Playback: %d:%d/%d:%d\n" - "Flags: %s\n" - "%s: %s\n", - play ? "play" : "stopped", - song_index + 1, plt_len, - pla_m, pla_s, dur_m, dur_s, - flags[0] ? flags : "(none)", - is_updating ? "Updating" : "Last update", buff); - - /* If there is a kara loaded in mpv, get this kara. */ - if (!stopped) { - printf("Kara: "); - current__(args); - } - - ret = EXIT_SUCCESS; -error: - exit(ret); -} - -noreturn void -queue_delete__(struct cmd_args *args) -{ - if (args->argc != 1) - fail("Invalid argument, need onlt one argument: queue delete <id>"); - - static const char *cmd_id__ = "deleteid %d\n"; - int dumy = 0; - FILE *sock = lkt_connect(); - char buff[3]; - - sscanf(args->argv[0], "%d", &dumy); - if (dumy != 0) { - write_socket(sock, cmd_id__, dumy); - exit_with_status(sock, buff); - } - - fail("Invalid argument"); -} - -noreturn void -queue_add__(struct cmd_args *args) -{ - char buff[3]; - fail_if(args->argc < 1, "Invalid arguments"); - fail_if(!lkt_valid_type(args->argv[0]), "Invalid query type"); - FILE *sock = lkt_connect(); - send_cmd_with_uri(sock, "add", args->argc, args->argv); - exit_with_status(sock, buff); -} - -noreturn void -queue_insert__(struct cmd_args *args) -{ - char buff[3]; - fail_if(args->argc < 1, "Invalid arguments"); - fail_if(!lkt_valid_type(args->argv[0]), "Invalid query type"); - FILE *sock = lkt_connect(); - send_cmd_with_uri(sock, "__insert", args->argc, args->argv); - exit_with_status(sock, buff); -} - -noreturn void -queue_seek__(struct cmd_args *args) -{ - fail_if(args->argc != 1, "The seek command needs one argument: queue seek <id>"); - - char *endptr, buf[3]; - long id = strtol(args->argv[0], &endptr, 0); - - if ((errno == ERANGE && (id == LONG_MAX || id == LONG_MIN)) || - (errno != 0 && id == 0) || - (endptr == args->argv[0])) - fail("Invalid argument, not an integer"); - - if (*endptr != '\0') - fail("Invalid argument, must be only one integer"); - - FILE *sock = lkt_connect(); - write_socket(sock, "playid %ld\n", id); - exit_with_status(sock, buf); -} - -noreturn void -queue_pos__(struct cmd_args *args) -{ - char buff[LKT_MESSAGE_MAX], *endptr; - - if (args->argc != 1) - fail("Invalid argument for the pos command: queue pos <arg> where arg is a position or a range"); - - long continuation = 0, up = 0; - - continuation = strtol(args->argv[0], &endptr, 0); - if ((errno == ERANGE && (continuation == LONG_MAX || continuation == LONG_MIN)) || (errno != 0 - && continuation == 0) || (endptr == args->argv[0])) - fail("Invalid argument, not an integer: queue pos <arg> where arg is a position or a range"); - - if (*endptr != '\0') { - /* A range */ - if (*(++endptr) == '\0') - fail("Invalid argument, a range is two integers"); - up = atoi(endptr); - } - - - FILE *sock = NULL; -redo: - sock = lkt_connect(); - if (up != 0) - write_socket(sock, "playlist %d:%d\n", continuation, up); - else - write_socket(sock, "playlist %d\n", continuation); - - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - - if (STR_NMATCH(buff, "continue:", strlen("continue:"))) { - continuation = atoi(lkt_skip_key(buff)); - if (continuation > 0) { - fclose(sock); - goto redo; - } - } - - if (STR_NMATCH(buff, "OK", 2)) - exit(EXIT_SUCCESS); - else if (STR_NMATCH(buff, "ACK", 3)) - exit(EXIT_FAILURE); - - fprintf(stdout, "%s", buff); - } -} - -noreturn void -queue_list__(struct cmd_args *args) -{ - char buff[LKT_MESSAGE_MAX], *endptr; - FILE *sock = NULL; - long continuation = 0, song_index = 1; - - /* Arguments stuff. */ - - if (args->argc == 0) - args->argv = LKT_QUEUE_DEFAULT; - else if (args->argc != 1) - fail("Invalid argument: queue <count?>"); - - continuation = strtol(args->argv[0], &endptr, 0); - if ((errno == ERANGE && (continuation == LONG_MAX || continuation == LONG_MIN)) || (errno != 0 - && continuation == 0) || (endptr == args->argv[0])) - fail("Invalid argument, not an integer"); - - if (*endptr != '\0') - fail("Invalid argument"); - - /* Get the current pos to get limits for the playlist command. */ - - sock = lkt_connect(); - write_socket(sock, "status\n"); - -#define assign_int(str, var) if (STR_NMATCH(buff, str, len)) { var = (atoi(lkt_skip_key(buff))); continue; } - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - size_t len = strcspn(buff, LKT_KEY_VALUE_SEP); - assign_int("song", song_index); - - /* At this point every key has been parsed. */ - if (STR_NMATCH(buff, "OK", 2)) - break; - else if (STR_NMATCH(buff, "ACK", 3)) - exit(EXIT_FAILURE); - } -#undef assign_int - fclose(sock); - - /* Get the content of the queue. */ - - continuation = labs(continuation); - song_index = MAX(song_index + 1, 1); - safe_snprintf(buff, LKT_MESSAGE_MAX, "%ld:%ld", song_index, song_index + continuation - 1); - args->argc = 1; - args->argv[0] = buff; - queue_pos__(args); -} - -/* Functions implementing options, but for for playlists. */ - -noreturn void -plt_add__(struct cmd_args *args) -{ - char buff[2]; - FILE *sock = lkt_connect(); - fail_if(args->argc < 3, - "Invalid argument, need at least three arguments: plt add <plt> <query>"); - fail_if(!lkt_valid_type(args->argv[1]), "Invalid argument, type for the query is invalid"); - - int i; - char buf[LKT_MESSAGE_MAX] = {0}; - for (i = 2; i < args->argc - 1; ++i) { - strncat(buf, args->argv[i], LKT_MESSAGE_MAX - 1); - strncat(buf, " ", LKT_MESSAGE_MAX - 1); - } - strncat(buf, args->argv[i], LKT_MESSAGE_MAX - 1); - strncat(buf, "\n", LKT_MESSAGE_MAX - 1); - write_socket(sock, "playlistadd %s %s://%s", args->argv[0], args->argv[1], buf); - - exit_with_status(sock, buff); -} - -noreturn void -plt_delete__(struct cmd_args *args) -{ - FILE *sock = lkt_connect(); - char buff[2]; - char cmd[128]; - fail_if(args->argc < 3, "Invalid argument"); - snprintf(cmd, 128 - 1, "playlistdelete %s", args->argv[0]); - cmd[127] = '\0'; - send_cmd_with_uri(sock, cmd, args->argc - 1, &args->argv[1]); - exit_with_status(sock, buff); -} - -noreturn void -stickers_get__(struct cmd_args *args) -{ - char buff[LKT_MESSAGE_MAX]; - FILE *sock; - if (args->argc == 2) - write_socket(sock = lkt_connect(), "sticker get %s %s\n", args->argv[0], args->argv[1]); - else if (args->argc == 3) - write_socket(sock = lkt_connect(), "sticker get %s %s %s\n", args->argv[0], args->argv[1], - args->argv[2]); - else if (args->argc == 5) { - const char *op = args->argv[3]; - op = op[0] == 'e' ? "=" : op[0] == 'l' ? "<" : op[0] == 'g' ? ">" : NULL; - fail_if(!op, "Invalid argument"); - write_socket(sock = lkt_connect(), "sticker get %s %s %s %s %s\n", args->argv[0], - args->argv[1], args->argv[2], op, args->argv[4]); - } else - fail("Invalid argument"); - - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - if (STR_NMATCH(buff, "OK", 2)) - exit(EXIT_SUCCESS); - else if (STR_NMATCH(buff, "ACK", 3)) - exit(EXIT_FAILURE); - fprintf(stdout, "%s", buff); - } -} - -noreturn void -stickers_set__(struct cmd_args *args) -{ - fail_if(args->argc != 4, "Invalid argument"); - FILE *sock = lkt_connect(); - char buff[2]; - write_socket(sock, "sticker set %s %s %s %s\n", args->argv[0], - args->argv[1], args->argv[2], args->argv[3]); - exit_with_status(sock, buff); -} - -noreturn void -stickers_delete__(struct cmd_args *args) -{ - FILE *sock; - char buff[2]; - if (args->argc == 2) - write_socket(sock = lkt_connect(), "sticker delete %s %s", - args->argv[0], args->argv[1]); - else if (args->argc == 3) - write_socket(sock = lkt_connect(), "sticker delete %s %s %s", - args->argv[0], args->argv[1], args->argv[2]); - else - fail("Invalid argument"); - exit_with_status(sock, buff); -} - -/* Search functions. */ - -noreturn void -__continuation_calls(const char *cmd) -{ - char buff[LKT_MESSAGE_MAX]; - int continuation = 0; - FILE *sock = NULL; -redo: - sock = lkt_connect(); - - write_socket(sock, "%d %s\n", continuation, cmd); - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - - if (STR_NMATCH(buff, "continue:", strlen("continue:"))) { - continuation = atoi(lkt_skip_key(buff)); - fclose(sock); - goto redo; - } - - if (STR_NMATCH(buff, "OK", 2)) - exit(EXIT_SUCCESS); - else if (STR_NMATCH(buff, "ACK", 3)) - exit(EXIT_FAILURE); - - fprintf(stdout, "%s", buff); - } -} - -noreturn void -list_plt__(struct cmd_args *args) -{ - fail_if(args->argc != 0, "Invalid argument number"); - __continuation_calls("listplaylists"); -} - -noreturn void -list_plt_content__(struct cmd_args *args) -{ - fail_if(args->argc != 1, "Invalid argument number"); - char buff[LKT_MESSAGE_MAX]; - safe_snprintf(buff, LKT_MESSAGE_MAX, "listplaylist %s", args->argv[0]); - __continuation_calls(buff); - exit(EXIT_FAILURE); -} - -noreturn void -search_with_cmd__(struct cmd_args *args, const char *cmd) -{ - fail_if(args->argc < 2, "Invalid number of arguments"); - fail_if(!lkt_valid_type(args->argv[0]), "Invalid type for the query"); - - char buff[LKT_MESSAGE_MAX]; - int continuation = 0, i; - FILE *sock = NULL; -redo: - sock = lkt_connect(); - - write_socket(sock, "%d %s %s://", continuation, cmd, args->argv[0]); - for (i = 1; i < args->argc - 1; ++i) - write_socket(sock, "%s ", args->argv[i]); - write_socket(sock, "%s\n", args->argv[i]); - - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - - if (STR_NMATCH(buff, "continue:", strlen("continue:"))) { - continuation = atoi(lkt_skip_key(buff)); - fclose(sock); - goto redo; - } - - if (STR_NMATCH(buff, "OK", 2)) - exit(EXIT_SUCCESS); - else if (STR_NMATCH(buff, "ACK", 3)) - exit(EXIT_FAILURE); - - fprintf(stdout, "%s", buff); - } -} - -noreturn void -search_get__(struct cmd_args *args) -{ - fail_if(args->argc != 1, "Invalid number of arguments"); - fail_if(!strtol(args->argv[0], NULL, 0), "Invalid id"); - char buff[LKT_MESSAGE_MAX]; - FILE *sock = lkt_connect(); - - write_socket(sock, "find %s\n", args->argv[0]); - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - if (STR_NMATCH(buff, "OK", 2)) - exit(EXIT_SUCCESS); - else if (STR_NMATCH(buff, "ACK", 3)) - exit(EXIT_FAILURE); - (void) write(1, buff, strlen(buff)); - } -} - -noreturn void -search_plt__(struct cmd_args *args) -{ - if (args->argc == 0) - list_plt__(args); - if (args->argc == 1) - list_plt_content__(args); - - fail_if(args->argc < 3, "Invalid number of arguments"); - fail_if(!lkt_valid_type(args->argv[1]), "Invalid type for query"); - char buff[LKT_MESSAGE_MAX]; - int continuation = 0, i; - FILE *sock = NULL; -redo: - sock = lkt_connect(); - - write_socket(sock, "%d listplaylistinfo %s %s://", continuation, - args->argv[0], args->argv[1]); - for (i = 2; i < args->argc - 1; ++i) - write_socket(sock, "%s ", args->argv[i]); - write_socket(sock, "%s\n", args->argv[i]); - - for (;;) { - memset(buff, 0, LKT_MESSAGE_MAX * sizeof(char)); - read_socket(sock, buff, LKT_MESSAGE_MAX - 1); - - if (STR_NMATCH(buff, "continue:", strlen("continue:"))) { - continuation = atoi(lkt_skip_key(buff)); - fclose(sock); - goto redo; - } - - if (STR_NMATCH(buff, "OK", 2)) - exit(EXIT_SUCCESS); - else if (STR_NMATCH(buff, "ACK", 3)) - exit(EXIT_FAILURE); - - fprintf(stdout, "%s", buff); - } -} - -#define search_with_cmd(func, cmd) /* I don't want to write always the same things */ \ - noreturn void func (struct cmd_args *args) { search_with_cmd__(args, #cmd); } -search_with_cmd(search_db__, search) -search_with_cmd(search_count__, count) -search_with_cmd(search_queue__, playlistfind) -#undef search_with_cmd - -/* Parsing stuff. */ - -static struct cmd_opt options_queue[] = { - { .name = "insert", .call = queue_insert__ }, - { .name = "pos", .call = queue_pos__ }, - { .name = "pop", .call = queue_pop__ }, - { .name = "add", .call = queue_add__ }, - { .name = "seek", .call = queue_seek__ }, - { .name = "delete", .call = queue_delete__ }, - { .name = "clear", .call = queue_clear__ }, - { .name = "crop", .call = queue_crop__ }, - { .name = "replace", .call = queue_replace__ }, - { .name = "dump", .call = queue_dump__ }, - CMD_OPT_DEFAULT(queue_list__), -}; - -static struct cmd_opt options_plt[] = { - { .name = "add", .call = plt_add__ }, - { .name = "delete", .call = plt_delete__ }, - { .name = "destroy", .call = plt_destroy__ }, - { .name = "create", .call = plt_create__ }, - { .name = "list", .call = search_plt__ }, - CMD_OPT_NULL, -}; - -static struct cmd_opt options_search[] = { - { .name = "database", .call = search_db__ }, - { .name = "get", .call = search_get__ }, - { .name = "plt", .call = search_plt__ }, - { .name = "count", .call = search_count__ }, - { .name = "queue", .call = search_queue__ }, - CMD_OPT_NULL, -}; - -static struct cmd_opt options_admin[] = { - { .name = "ping", .call = ping__ }, - { .name = "kill", .call = kill__ }, - { .name = "restart", .call = restart__ }, - { .name = "rescan", .call = rescan__ }, - { .name = "update", .call = update__ }, - { .name = "populate", .call = populate__ }, - { .name = "config", .call = config__ }, - CMD_OPT_NULL, -}; - -static struct cmd_opt options_stickers[] = { - { .name = "get", .call = stickers_get__ }, - { .name = "set", .call = stickers_set__ }, - { .name = "delete", .call = stickers_delete__ }, - { .name = "create", .call = stickers_create__ }, - { .name = "destroy", .call = stickers_destroy__ }, - CMD_OPT_NULL, -}; - -#define sub_command(name) /* Create sub-commands here */ \ - noreturn void name ## __(struct cmd_args *args) { \ - fail_if(!args->argc, "Invalid command, specify a sub command for " #name); \ - cmd_parse(options_ ## name, args->argc, args->argv); \ - } -sub_command(stickers) -sub_command(search) -sub_command(plt) -sub_command(admin) - -noreturn void -queue__(struct cmd_args *args) -{ - if (args->argc == 0) - queue_list__(args); - cmd_parse(options_queue, args->argc, args->argv); -} -#undef sub_command - -static struct cmd_opt options_[] = { - { .name = "current", .call = current__ }, - { .name = "play", .call = play__ }, - { .name = "next", .call = next__ }, - { .name = "previous", .call = prev__ }, - { .name = "queue", .call = queue__ }, - { .name = "shuffle", .call = shuffle__ }, - { .name = "status", .call = status__ }, - { .name = "stop", .call = stop__ }, - { .name = "plt", .call = plt__ }, - { .name = "search", .call = search__ }, - { .name = "admin", .call = admin__ }, - { .name = "stickers", .call = stickers__ }, - CMD_OPT_NULL, -}; - -/* The sigpipe function, if SIGPIPE signal is sent. */ - -static void -sigpipe__(int sig) -{ - LOG_ERROR("GENERAL", "Exit because of signal sigpipe (%d)", sig); - exit(EXIT_FAILURE); -} - -/* Functions declarations. */ - -static void -parse_args(args_t *args, int argc, const char **argv) -{ - int i, got = 0; - size_t len; - - for (i = 1; i < argc && i < 3; ++i) { - len = strcspn(argv[i], "="); - - if (STR_NMATCH("host", argv[i], len)) { - args->host = (argv[i] + len + 1); - ++got; - } - - else if (STR_NMATCH("port", argv[i], len)) { - args->port = (argv[i] + len + 1); - ++got; - } - - else if (STR_NMATCH("pwd", argv[i], len)) { - args->pwd = (argv[i] + len + 1); - ++got; - } - } - - args->argv = &argv[got + 1]; - args->argc = argc - (got + 1); -} - -int -main(int argc, const char **argv) -{ - __log_level = ERROR; - executable_name = "lkt"; - assert(NULL != setlocale(LC_ALL, "en_US.UTF-8")); /* BECAUSE! */ - if (signal(SIGPIPE, sigpipe__)) { - // LOG_ERROR("SYS", "%s", "Failed to install handler for SIGPIPE signal"); - } - - args_t args = { - .host = "localhost", - .port = "6600", - }; - - parse_args(&args, argc, argv); - - host = args.host; - port = args.port; - password = args.pwd; - - /* Communication with lektor. */ - cmd_parse(options_, args.argc, args.argv); -} diff --git a/src/main/lkt.c b/src/main/lkt.c index ccb02b2ae7f3c800883e8e6d6393323efa0c646b..5edcc32dfb5c191d7dd241627abb2ba340827105 100644 --- a/src/main/lkt.c +++ b/src/main/lkt.c @@ -355,6 +355,12 @@ update__(struct cmd_args *args) rescan_or_update__(args, "update"); } +noreturn void +import__(struct cmd_args *args) +{ + rescan_or_update__(args, "import"); +} + noreturn void populate__(struct cmd_args *args) { @@ -1120,6 +1126,7 @@ static struct cmd_opt options_admin[] = { { .name = "update", .call = update__ }, { .name = "populate", .call = populate__ }, { .name = "config", .call = config__ }, + { .name = "import", .call = import__ }, CMD_OPT_NULL, };