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