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