1 /* libmpdclient
2    (c) 2003-2019 The Music Player Daemon Project
3    This project's homepage is: http://www.musicpd.org
4 
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
8 
9    - Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11 
12    - Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15 
16    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
20    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
24    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include <mpd/send.h>
30 
31 #include "isend.h"
32 #include "internal.h"
33 #include "sync.h"
34 
35 #include <stdarg.h>
36 #include <limits.h>
37 #include <stdio.h>
38 
39 /* (bits+1)/3 (plus the sign character) */
40 enum {
41 	INTLEN = (sizeof(int) * CHAR_BIT + 1) / 3 + 1,
42 	LONGLONGLEN = (sizeof(long long) * CHAR_BIT + 1) / 3 + 1,
43 	FLOATLEN = LONGLONGLEN + 8,
44 };
45 
46 static void
format_range(char * buffer,size_t size,unsigned start,unsigned end)47 format_range(char *buffer, size_t size, unsigned start, unsigned end)
48 {
49 	if (end == UINT_MAX)
50 		/* the special value -1 means "open end" */
51 		snprintf(buffer, size, "%u:", start);
52 	else
53 		snprintf(buffer, size, "%u:%u", start, end);
54 }
55 
56 static void
format_frange(char * buffer,size_t size,float start,float end)57 format_frange(char *buffer, size_t size, float start, float end)
58 {
59 	/* the special value 0.0 means "open range" */
60 	if (end >= 0)
61 		snprintf(buffer, size, "%1.3f:%1.3f", start, end);
62 	else
63 		snprintf(buffer, size, "%1.3f:", start);
64 }
65 
66 /**
67  * Checks whether it is possible to send a command now.
68  */
69 static bool
send_check(struct mpd_connection * connection)70 send_check(struct mpd_connection *connection)
71 {
72 	assert(connection != NULL);
73 
74 	if (mpd_error_is_defined(&connection->error))
75 		return false;
76 
77 	if (connection->receiving) {
78 		mpd_error_code(&connection->error, MPD_ERROR_STATE);
79 		mpd_error_message(&connection->error,
80 				  "Cannot send a new command while "
81 				  "receiving another response");
82 		return false;
83 	}
84 
85 	return true;
86 }
87 
88 bool
mpd_send_command(struct mpd_connection * connection,const char * command,...)89 mpd_send_command(struct mpd_connection *connection, const char *command, ...)
90 {
91 	va_list ap;
92 	bool success;
93 
94 	if (!send_check(connection))
95 		return false;
96 
97 	va_start(ap, command);
98 
99 	success = mpd_sync_send_command_v(connection->async,
100 					  mpd_connection_timeout(connection),
101 					  command, ap);
102 
103 	va_end(ap);
104 
105 	if (!success) {
106 		mpd_connection_sync_error(connection);
107 		return false;
108 	}
109 
110 	if (!connection->sending_command_list) {
111 		/* the caller might expect that we have flushed the
112 		   output buffer when this function returns */
113 		if (!mpd_flush(connection))
114 			return false;
115 
116 		connection->receiving = true;
117 	} else if (connection->sending_command_list_ok)
118 		++connection->command_list_remaining;
119 
120 	return true;
121 }
122 
123 bool
mpd_send_command2(struct mpd_connection * connection,const char * command)124 mpd_send_command2(struct mpd_connection *connection, const char *command)
125 {
126 	bool success;
127 
128 	if (!send_check(connection))
129 		return false;
130 
131 	success = mpd_sync_send_command(connection->async,
132 					mpd_connection_timeout(connection),
133 					command, NULL);
134 	if (!success) {
135 		mpd_connection_sync_error(connection);
136 		return false;
137 	}
138 
139 	return true;
140 }
141 
142 bool
mpd_send_int_command(struct mpd_connection * connection,const char * command,int arg)143 mpd_send_int_command(struct mpd_connection *connection, const char *command,
144 		     int arg)
145 {
146 	char arg_string[INTLEN];
147 
148 	snprintf(arg_string, sizeof(arg_string), "%i", arg);
149 	return mpd_send_command(connection, command, arg_string, NULL);
150 }
151 
152 bool
mpd_send_int2_command(struct mpd_connection * connection,const char * command,int arg1,int arg2)153 mpd_send_int2_command(struct mpd_connection *connection, const char *command,
154 		      int arg1, int arg2)
155 {
156 	char arg1_string[INTLEN], arg2_string[INTLEN];
157 
158 	snprintf(arg1_string, sizeof(arg1_string), "%i", arg1);
159 	snprintf(arg2_string, sizeof(arg2_string), "%i", arg2);
160 	return mpd_send_command(connection, command,
161 				arg1_string, arg2_string, NULL);
162 }
163 
164 bool
mpd_send_int3_command(struct mpd_connection * connection,const char * command,int arg1,int arg2,int arg3)165 mpd_send_int3_command(struct mpd_connection *connection, const char *command,
166 		      int arg1, int arg2, int arg3)
167 {
168 	char arg1_string[INTLEN], arg2_string[INTLEN], arg3_string[INTLEN];
169 
170 	snprintf(arg1_string, sizeof(arg1_string), "%i", arg1);
171 	snprintf(arg2_string, sizeof(arg2_string), "%i", arg2);
172 	snprintf(arg3_string, sizeof(arg3_string), "%i", arg3);
173 	return mpd_send_command(connection, command,
174 				arg1_string, arg2_string, arg3_string, NULL);
175 }
176 
177 bool
mpd_send_float_command(struct mpd_connection * connection,const char * command,float arg)178 mpd_send_float_command(struct mpd_connection *connection, const char *command,
179 		       float arg)
180 {
181 	char arg_string[FLOATLEN];
182 
183 	snprintf(arg_string, sizeof(arg_string), "%f", arg);
184 	return mpd_send_command(connection, command, arg_string, NULL);
185 }
186 
187 bool
mpd_send_u_command(struct mpd_connection * connection,const char * command,unsigned arg1)188 mpd_send_u_command(struct mpd_connection *connection, const char *command,
189 		     unsigned arg1)
190 {
191 	char arg1_string[INTLEN];
192 
193 	snprintf(arg1_string, sizeof(arg1_string), "%u", arg1);
194 	return mpd_send_command(connection, command,
195 				arg1_string, NULL);
196 }
197 
198 bool
mpd_send_u_f_command(struct mpd_connection * connection,const char * command,unsigned arg1,float arg2)199 mpd_send_u_f_command(struct mpd_connection *connection, const char *command,
200 		     unsigned arg1, float arg2)
201 {
202 	char arg1_string[INTLEN], arg2_string[FLOATLEN];
203 
204 	snprintf(arg1_string, sizeof(arg1_string), "%u", arg1);
205 	snprintf(arg2_string, sizeof(arg2_string), "%.3f", arg2);
206 	return mpd_send_command(connection, command,
207 				arg1_string, arg2_string, NULL);
208 }
209 
210 bool
mpd_send_u_s_command(struct mpd_connection * connection,const char * command,unsigned arg1,const char * arg2)211 mpd_send_u_s_command(struct mpd_connection *connection, const char *command,
212 		     unsigned arg1, const char *arg2)
213 {
214 	char arg1_string[INTLEN];
215 
216 	snprintf(arg1_string, sizeof(arg1_string), "%i", arg1);
217 	return mpd_send_command(connection, command,
218 				arg1_string, arg2, NULL);
219 }
220 
221 bool
mpd_send_u_s_s_command(struct mpd_connection * connection,const char * command,unsigned arg1,const char * arg2,const char * arg3)222 mpd_send_u_s_s_command(struct mpd_connection *connection, const char *command,
223 		       unsigned arg1, const char *arg2, const char *arg3)
224 {
225 	char arg1_string[INTLEN];
226 
227 	snprintf(arg1_string, sizeof(arg1_string), "%i", arg1);
228 	return mpd_send_command(connection, command,
229 				arg1_string, arg2, arg3, NULL);
230 }
231 
232 bool
mpd_send_s_s_command(struct mpd_connection * connection,const char * command,const char * arg1,const char * arg2)233 mpd_send_s_s_command(struct mpd_connection *connection, const char *command,
234 		       const char *arg1, const char *arg2)
235 {
236 	return mpd_send_command(connection, command,
237 				arg1, arg2, NULL);
238 }
239 
240 bool
mpd_send_s_u_command(struct mpd_connection * connection,const char * command,const char * arg1,unsigned arg2)241 mpd_send_s_u_command(struct mpd_connection *connection, const char *command,
242 		     const char *arg1, unsigned arg2)
243 {
244 	char arg2_string[INTLEN];
245 
246 	snprintf(arg2_string, sizeof(arg2_string), "%u", arg2);
247 	return mpd_send_command(connection, command,
248 				arg1, arg2_string, NULL);
249 }
250 
251 bool
mpd_send_s_s_u_command(struct mpd_connection * connection,const char * command,const char * arg1,const char * arg2,unsigned arg3)252 mpd_send_s_s_u_command(struct mpd_connection *connection, const char *command,
253 		     const char *arg1, const char *arg2, unsigned arg3)
254 {
255 	char arg3_string[INTLEN];
256 
257 	snprintf(arg3_string, sizeof(arg3_string), "%u", arg3);
258 	return mpd_send_command(connection, command,
259 				arg1, arg2, arg3_string, NULL);
260 }
261 
262 bool
mpd_send_range_command(struct mpd_connection * connection,const char * command,unsigned arg1,unsigned arg2)263 mpd_send_range_command(struct mpd_connection *connection, const char *command,
264                        unsigned arg1, unsigned arg2)
265 {
266 	char arg_string[INTLEN*2+1];
267 
268 	format_range(arg_string, sizeof(arg_string), arg1, arg2);
269 	return mpd_send_command(connection, command, arg_string, NULL);
270 }
271 
272 bool
mpd_send_s_range_command(struct mpd_connection * connection,const char * command,const char * arg1,unsigned start,unsigned end)273 mpd_send_s_range_command(struct mpd_connection *connection,
274 			 const char *command, const char *arg1,
275 			 unsigned start, unsigned end)
276 {
277 	char range_string[INTLEN * 2 + 1];
278 
279 	format_range(range_string, sizeof(range_string), start, end);
280 	return mpd_send_command(connection, command,
281 				arg1, range_string, NULL);
282 }
283 
284 bool
mpd_send_s_range_to_command(struct mpd_connection * connection,const char * command,const char * arg1,unsigned start,unsigned end,char * to)285 mpd_send_s_range_to_command(struct mpd_connection *connection,
286 			 const char *command, const char *arg1,
287 			 unsigned start, unsigned end, char *to)
288 {
289 	char range_string[INTLEN * 2 + 1];
290 
291 	format_range(range_string, sizeof(range_string), start, end);
292 	return mpd_send_command(connection, command,
293 				arg1, range_string, to, NULL);
294 }
295 
296 bool
mpd_send_i_range_command(struct mpd_connection * connection,const char * command,int arg1,unsigned start,unsigned end)297 mpd_send_i_range_command(struct mpd_connection *connection,
298 			 const char *command, int arg1,
299 			 unsigned start, unsigned end)
300 {
301 	char arg1_string[INTLEN + 1], arg2_string[INTLEN * 2 + 1];
302 
303 	snprintf(arg1_string, sizeof(arg1_string), "%i", arg1);
304 	format_range(arg2_string, sizeof(arg2_string), start, end);
305 	return mpd_send_command(connection, command,
306 				arg1_string, arg2_string, NULL);
307 }
308 
309 bool
mpd_send_u_range_command(struct mpd_connection * connection,const char * command,unsigned arg1,unsigned start,unsigned end)310 mpd_send_u_range_command(struct mpd_connection *connection,
311 			 const char *command, unsigned arg1,
312 			 unsigned start, unsigned end)
313 {
314 	char arg1_string[INTLEN + 1], arg2_string[INTLEN * 2 + 1];
315 
316 	snprintf(arg1_string, sizeof(arg1_string), "%u", arg1);
317 	format_range(arg2_string, sizeof(arg2_string), start, end);
318 	return mpd_send_command(connection, command,
319 				arg1_string, arg2_string, NULL);
320 }
321 
322 bool
mpd_send_range_u_command(struct mpd_connection * connection,const char * command,unsigned start,unsigned end,unsigned arg2)323 mpd_send_range_u_command(struct mpd_connection *connection,
324 			 const char *command,
325 			 unsigned start, unsigned end, unsigned arg2)
326 {
327 	char arg1_string[INTLEN*2+1], arg2_string[INTLEN];
328 
329 	format_range(arg1_string, sizeof(arg1_string), start, end);
330 	snprintf(arg2_string, sizeof(arg2_string), "%i", arg2);
331 	return mpd_send_command(connection, command,
332 				arg1_string, arg2_string, NULL);
333 }
334 
335 bool
mpd_send_u_frange_command(struct mpd_connection * connection,const char * command,unsigned arg1,float start,float end)336 mpd_send_u_frange_command(struct mpd_connection *connection,
337 			 const char *command, unsigned arg1,
338 			 float start, float end)
339 {
340 	/* <start>:<end> */
341 	char arg1_string[INTLEN + 1];
342 	char range_string[FLOATLEN * 2 + 1 + 1];
343 
344 	snprintf(arg1_string, sizeof(arg1_string), "%u", arg1);
345 	format_frange(range_string, sizeof(range_string), start, end);
346 
347 	return mpd_send_command(connection, command,
348 				arg1_string, range_string, NULL);
349 }
350 
351 bool
mpd_send_ll_command(struct mpd_connection * connection,const char * command,long long arg)352 mpd_send_ll_command(struct mpd_connection *connection, const char *command,
353 		    long long arg)
354 {
355 	char arg_string[LONGLONGLEN];
356 
357 #ifdef _WIN32
358 	snprintf(arg_string, sizeof(arg_string), "%ld", (long)arg);
359 #else
360 	snprintf(arg_string, sizeof(arg_string), "%lld", arg);
361 #endif
362 	return mpd_send_command(connection, command, arg_string, NULL);
363 }
364 
365 bool
mpd_flush(struct mpd_connection * connection)366 mpd_flush(struct mpd_connection *connection)
367 {
368 	if (!mpd_sync_flush(connection->async,
369 			    mpd_connection_timeout(connection))) {
370 		mpd_connection_sync_error(connection);
371 		return false;
372 	}
373 
374 	return true;
375 }
376