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