chiark / gitweb /
Thinko in menu option l-)
[disorder] / server / plugin.c
1 /*
2  * This file is part of DisOrder.
3  * Copyright (C) 2004-2008 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 struct plugin {
32   struct plugin *next;
33   void *dlhandle;
34   const char *name;
35 };
36
37 static struct plugin *plugins;
38
39 const 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;
49   /* Search the plugin path */
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         disorder_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 ? disorder_fatal : disorder_error)
69     (0, "cannot find plugin '%s'", name);
70   return 0;
71 }
72
73 function_t *get_plugin_function(const struct plugin *pl,
74                                 const char *symbol) {
75   function_t *f;
76
77   f = (function_t *)dlsym(pl->dlhandle, symbol);
78   if(!f)
79     disorder_fatal(0, "error looking up function '%s' in '%s': %s",
80                    symbol, pl->name, dlerror());
81   return f;
82 }
83
84 const void *get_plugin_object(const struct plugin *pl,
85                               const char *symbol) {
86   void *o;
87
88   o = dlsym(pl->dlhandle, symbol);
89   if(!o)
90     disorder_fatal(0, "error looking up object '%s' in '%s': %s",
91                    symbol, pl->name, dlerror());
92   return o;
93 }
94
95 /* specific plugin interfaces *************************************************/
96
97 typedef long tracklength_fn(const char *track, const char *path);
98
99 /** Compute the length of a track
100  * @param plugin plugin to use, as configured
101  * @param track UTF-8 name of track
102  * @param path file system path or 0
103  * @return length of track in seconds, 0 for unknown, -1 for error
104  */
105 long tracklength(const char *plugin, const char *track, const char *path) {
106   tracklength_fn *f = 0;
107
108   f = (tracklength_fn *)get_plugin_function(open_plugin(plugin,
109                                                         PLUGIN_FATAL),
110                                             "disorder_tracklength");
111   return (*f)(track, path);
112 }
113
114 typedef void scan_fn(const char *root);
115
116 void scan(const char *module, const char *root) {
117   ((scan_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
118                                   "disorder_scan"))(root);
119 }
120
121 typedef int check_fn(const char *root, const char *path);
122
123
124 int check(const char *module, const char *root, const char *path) {
125   return ((check_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
126                                           "disorder_check"))(root, path);
127 }
128
129 typedef void notify_play_fn(const char *track, const char *submitter);
130
131 void notify_play(const char *track,
132                  const char *submitter) {
133   static notify_play_fn *f;
134
135   if(!f)
136     f = (notify_play_fn *)get_plugin_function(open_plugin("notify",
137                                                           PLUGIN_FATAL),
138                                               "disorder_notify_play");
139   (*f)(track, submitter);
140 }
141
142 typedef void notify_scratch_fn(const char *track,
143                                const char *submitter,
144                                const char *scratcher,
145                                int seconds);
146
147 void notify_scratch(const char *track,
148                     const char *submitter,
149                     const char *scratcher,
150                     int seconds) {
151   static notify_scratch_fn *f;
152
153   if(!f)
154     f = (notify_scratch_fn *)get_plugin_function(open_plugin("notify",
155                                                              PLUGIN_FATAL),
156                                                  "disorder_notify_scratch");
157   (*f)(track, submitter, scratcher, seconds);
158 }
159
160 typedef void notify_not_scratched_fn(const char *track,
161                                      const char *submitter);
162
163 void notify_not_scratched(const char *track,
164                           const char *submitter) {
165   static notify_not_scratched_fn *f;
166
167   if(!f)
168     f = (notify_not_scratched_fn *)get_plugin_function
169       (open_plugin("notify",
170                    PLUGIN_FATAL),
171        "disorder_notify_not_scratched");
172   (*f)(track, submitter);
173 }
174
175 typedef void notify_queue_fn(const char *track,
176                              const char *submitter);
177
178 void notify_queue(const char *track,
179                   const char *submitter) {
180   static notify_queue_fn *f;
181
182   if(!f)
183     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
184                                                            PLUGIN_FATAL),
185                                                "disorder_notify_queue");
186   (*f)(track, submitter);
187 }
188
189 void notify_queue_remove(const char *track,
190                          const char *remover) {
191   static notify_queue_fn *f;
192   
193   if(!f)
194     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
195                                                            PLUGIN_FATAL),
196                                                "disorder_notify_queue_remove");
197   (*f)(track, remover);
198 }
199
200 void notify_queue_move(const char *track,
201                        const char *mover) {
202   static notify_queue_fn *f;
203   
204   if(!f)
205     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
206                                                            PLUGIN_FATAL),
207                                                "disorder_notify_queue_move");
208   (*f)(track, mover);
209 }
210
211 void notify_pause(const char *track, const char *who) {
212   static notify_queue_fn *f;
213   
214   if(!f)
215     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
216                                                            PLUGIN_FATAL),
217                                                "disorder_notify_pause");
218   (*f)(track, who);
219 }
220
221 void notify_resume(const char *track, const char *who) {
222   static notify_queue_fn *f;
223   
224   if(!f)
225     f = (notify_queue_fn *)get_plugin_function(open_plugin("notify",
226                                                            PLUGIN_FATAL),
227                                                "disorder_notify_resume");
228   (*f)(track, who);
229 }
230
231 /* player plugin interfaces ***************************************************/
232
233 /* get type */
234
235 unsigned long play_get_type(const struct plugin *pl) {
236   return *(const unsigned long *)get_plugin_object(pl, "disorder_player_type");
237 }
238
239 /* prefork */
240
241 typedef void *prefork_fn(const char *track);
242
243 void *play_prefork(const struct plugin *pl,
244                    const char *track) {
245   return ((prefork_fn *)get_plugin_function(pl,
246                                             "disorder_play_prefork"))(track);
247 }
248
249 /* play */
250
251 typedef void play_track_fn(const char *const *parameters,
252                            int nparameters,
253                            const char *path,
254                            const char *track);
255
256 void play_track(const struct plugin *pl,
257                 const char *const *parameters,
258                 int nparameters,
259                 const char *path,
260                 const char *track) {
261   ((play_track_fn *)get_plugin_function(pl,
262                                         "disorder_play_track"))(parameters,
263                                                                 nparameters,
264                                                                 path,
265                                                                 track);
266 }
267
268 /* cleanup */
269
270 typedef void cleanup_fn(void *data);
271
272 void play_cleanup(const struct plugin *pl, void *data) {
273   ((cleanup_fn *)get_plugin_function(pl, "disorder_play_cleanup"))(data);
274 }
275
276 /* pause */
277
278 typedef int pause_fn(long *playedp, void *data);
279
280 int play_pause(const struct plugin *pl, long *playedp, void *data) {
281   return (((pause_fn *)get_plugin_function(pl, "disorder_pause_track"))
282           (playedp, data));
283 }
284
285 /* resume */
286
287 typedef void resume_fn(void *data);
288
289 void play_resume(const struct plugin *pl, void *data) {
290   (((resume_fn *)get_plugin_function(pl, "disorder_resume_track"))
291    (data));
292 }
293
294 /*
295 Local Variables:
296 c-basic-offset:2
297 comment-column:40
298 End:
299 */