chiark / gitweb /
Linux build fix
[disorder] / server / plugin.c
CommitLineData
460b9539 1/*
2 * This file is part of DisOrder.
5aff007d 3 * Copyright (C) 2004-2008 Richard Kettlewell
460b9539 4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18 * USA
19 */
20
05b75f8d 21#include "disorder-server.h"
460b9539 22
23#include <dlfcn.h>
460b9539 24
25/* generic plugin support *****************************************************/
26
27#ifndef SOSUFFIX
28# define SOSUFFIX ".so"
29#endif
30
31struct plugin {
32 struct plugin *next;
33 void *dlhandle;
34 const char *name;
35};
36
37static struct plugin *plugins;
38
39const struct plugin *open_plugin(const char *name,
40 unsigned flags) {
41 void *h = 0;
42 char *p;
43 int n;
44 struct plugin *pl;
45
46 for(pl = plugins; pl && strcmp(pl->name, name); pl = pl->next)
47 ;
48 if(pl) return pl;
62dc3748 49 /* Search the plugin path */
460b9539 50 for(n = 0; n <= config->plugins.n; ++n) {
51 byte_xasprintf(&p, "%s/%s" SOSUFFIX,
52 n == config->plugins.n ? pkglibdir : config->plugins.s[n],
53 name);
54 if(access(p, R_OK) == 0) {
55 h = dlopen(p, RTLD_NOW);
56 if(!h) {
57 error(0, "error opening %s: %s", p, dlerror());
58 continue;
59 }
60 pl = xmalloc(sizeof *pl);
61 pl->dlhandle = h;
62 pl->name = xstrdup(name);
63 pl->next = plugins;
64 plugins = pl;
65 return pl;
66 }
67 }
68 (flags & PLUGIN_FATAL ? fatal : error)(0, "cannot find plugin '%s'", name);
69 return 0;
70}
71
72function_t *get_plugin_function(const struct plugin *pl,
73 const char *symbol) {
74 function_t *f;
460b9539 75
76 f = (function_t *)dlsym(pl->dlhandle, symbol);
f47f3637 77 if(!f)
78 fatal(0, "error looking up function '%s' in '%s': %s",
79 symbol, pl->name, dlerror());
460b9539 80 return f;
81}
82
83const void *get_plugin_object(const struct plugin *pl,
84 const char *symbol) {
85 void *o;
460b9539 86
87 o = dlsym(pl->dlhandle, symbol);
f47f3637 88 if(!o)
89 fatal(0, "error looking up object '%s' in '%s': %s",
90 symbol, pl->name, dlerror());
460b9539 91 return o;
92}
93
94/* specific plugin interfaces *************************************************/
95
96typedef long tracklength_fn(const char *track, const char *path);
97
62dc3748
RK
98/** Compute the length of a track
99 * @param plugin plugin to use, as configured
100 * @param track UTF-8 name of track
101 * @param path file system path or 0
102 * @return length of track in seconds, 0 for unknown, -1 for error
103 */
104long tracklength(const char *plugin, const char *track, const char *path) {
105 tracklength_fn *f = 0;
460b9539 106
62dc3748
RK
107 f = (tracklength_fn *)get_plugin_function(open_plugin(plugin,
108 PLUGIN_FATAL),
109 "disorder_tracklength");
460b9539 110 return (*f)(track, path);
111}
112
113typedef void scan_fn(const char *root);
114
115void scan(const char *module, const char *root) {
116 ((scan_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
117 "disorder_scan"))(root);
118}
119
120typedef int check_fn(const char *root, const char *path);
121
122
123int check(const char *module, const char *root, const char *path) {
124 return ((check_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
125 "disorder_check"))(root, path);
126}
127
128typedef void notify_play_fn(const char *track, const char *submitter);
129
130void notify_play(const char *track,
131 const char *submitter) {
132 static notify_play_fn *f;
133
134 if(!f)
135 f = (notify_play_fn *)get_plugin_function(open_plugin("notify",
136 PLUGIN_FATAL),
137 "disorder_notify_play");
138 (*f)(track, submitter);
139}
140
141typedef void notify_scratch_fn(const char *track,
142 const char *submitter,
143 const char *scratcher,
144 int seconds);
145
146void notify_scratch(const char *track,
147 const char *submitter,
148 const char *scratcher,
149 int seconds) {
150 static notify_scratch_fn *f;
151
152 if(!f)
153 f = (notify_scratch_fn *)get_plugin_function(open_plugin("notify",
154 PLUGIN_FATAL),
155 "disorder_notify_scratch");
156 (*f)(track, submitter, scratcher, seconds);
157}
158
159typedef void notify_not_scratched_fn(const char *track,
160 const char *submitter);
161
162void notify_not_scratched(const char *track,
163 const char *submitter) {
164 static notify_not_scratched_fn *f;
165
166 if(!f)
167 f = (notify_not_scratched_fn *)get_plugin_function
168 (open_plugin("notify",
169 PLUGIN_FATAL),
170 "disorder_notify_not_scratched");
171 (*f)(track, submitter);
172}
173
174typedef void notify_queue_fn(const char *track,
175 const char *submitter);
176
177void notify_queue(const char *track,
178 const char *submitter) {
179 static notify_queue_fn *f;
180
181 if(!f)
182 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
183 PLUGIN_FATAL),
184 "disorder_notify_queue");
185 (*f)(track, submitter);
186}
187
188void notify_queue_remove(const char *track,
189 const char *remover) {
190 static notify_queue_fn *f;
191
192 if(!f)
193 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
194 PLUGIN_FATAL),
195 "disorder_notify_queue_remove");
196 (*f)(track, remover);
197}
198
199void notify_queue_move(const char *track,
200 const char *mover) {
201 static notify_queue_fn *f;
202
203 if(!f)
204 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
205 PLUGIN_FATAL),
206 "disorder_notify_queue_move");
207 (*f)(track, mover);
208}
209
210void notify_pause(const char *track, const char *who) {
211 static notify_queue_fn *f;
212
213 if(!f)
214 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
215 PLUGIN_FATAL),
216 "disorder_notify_pause");
217 (*f)(track, who);
218}
219
220void notify_resume(const char *track, const char *who) {
221 static notify_queue_fn *f;
222
223 if(!f)
224 f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
225 PLUGIN_FATAL),
226 "disorder_notify_resume");
227 (*f)(track, who);
228}
229
230/* player plugin interfaces ***************************************************/
231
232/* get type */
233
234unsigned long play_get_type(const struct plugin *pl) {
235 return *(const unsigned long *)get_plugin_object(pl, "disorder_player_type");
236}
237
238/* prefork */
239
240typedef void *prefork_fn(const char *track);
241
242void *play_prefork(const struct plugin *pl,
243 const char *track) {
244 return ((prefork_fn *)get_plugin_function(pl,
245 "disorder_play_prefork"))(track);
246}
247
248/* play */
249
250typedef void play_track_fn(const char *const *parameters,
251 int nparameters,
252 const char *path,
253 const char *track);
254
255void play_track(const struct plugin *pl,
256 const char *const *parameters,
257 int nparameters,
258 const char *path,
259 const char *track) {
260 ((play_track_fn *)get_plugin_function(pl,
261 "disorder_play_track"))(parameters,
262 nparameters,
263 path,
264 track);
265}
266
267/* cleanup */
268
269typedef void cleanup_fn(void *data);
270
271void play_cleanup(const struct plugin *pl, void *data) {
272 ((cleanup_fn *)get_plugin_function(pl, "disorder_play_cleanup"))(data);
273}
274
275/* pause */
276
277typedef int pause_fn(long *playedp, void *data);
278
279int play_pause(const struct plugin *pl, long *playedp, void *data) {
280 return (((pause_fn *)get_plugin_function(pl, "disorder_pause_track"))
281 (playedp, data));
282}
283
284/* resume */
285
286typedef void resume_fn(void *data);
287
288void play_resume(const struct plugin *pl, void *data) {
289 (((resume_fn *)get_plugin_function(pl, "disorder_resume_track"))
290 (data));
291}
292
293/*
294Local Variables:
295c-basic-offset:2
296comment-column:40
297End:
298*/