chiark / gitweb /
Switch to GPL v3
[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
19 #include "disorder-server.h"
20
21 #include <dlfcn.h>
22
23 /* generic plugin support *****************************************************/
24
25 #ifndef SOSUFFIX
26 # define SOSUFFIX ".so"
27 #endif
28
29 struct plugin {
30   struct plugin *next;
31   void *dlhandle;
32   const char *name;
33 };
34
35 static struct plugin *plugins;
36
37 const 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;
47   /* Search the plugin path */
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
70 function_t *get_plugin_function(const struct plugin *pl,
71                                 const char *symbol) {
72   function_t *f;
73
74   f = (function_t *)dlsym(pl->dlhandle, symbol);
75   if(!f)
76     fatal(0, "error looking up function '%s' in '%s': %s",
77           symbol, pl->name, dlerror());
78   return f;
79 }
80
81 const void *get_plugin_object(const struct plugin *pl,
82                               const char *symbol) {
83   void *o;
84
85   o = dlsym(pl->dlhandle, symbol);
86   if(!o)
87     fatal(0, "error looking up object '%s' in '%s': %s",
88           symbol, pl->name, dlerror());
89   return o;
90 }
91
92 /* specific plugin interfaces *************************************************/
93
94 typedef long tracklength_fn(const char *track, const char *path);
95
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  */
102 long tracklength(const char *plugin, const char *track, const char *path) {
103   tracklength_fn *f = 0;
104
105   f = (tracklength_fn *)get_plugin_function(open_plugin(plugin,
106                                                         PLUGIN_FATAL),
107                                             "disorder_tracklength");
108   return (*f)(track, path);
109 }
110
111 typedef void scan_fn(const char *root);
112
113 void scan(const char *module, const char *root) {
114   ((scan_fn *)get_plugin_function(open_plugin(module, PLUGIN_FATAL),
115                                   "disorder_scan"))(root);
116 }
117
118 typedef int check_fn(const char *root, const char *path);
119
120
121 int 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
126 typedef void notify_play_fn(const char *track, const char *submitter);
127
128 void 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
139 typedef void notify_scratch_fn(const char *track,
140                                const char *submitter,
141                                const char *scratcher,
142                                int seconds);
143
144 void 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
157 typedef void notify_not_scratched_fn(const char *track,
158                                      const char *submitter);
159
160 void 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
172 typedef void notify_queue_fn(const char *track,
173                              const char *submitter);
174
175 void 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
186 void 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
197 void 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
208 void 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
218 void 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
232 unsigned 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
238 typedef void *prefork_fn(const char *track);
239
240 void *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
248 typedef void play_track_fn(const char *const *parameters,
249                            int nparameters,
250                            const char *path,
251                            const char *track);
252
253 void 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
267 typedef void cleanup_fn(void *data);
268
269 void play_cleanup(const struct plugin *pl, void *data) {
270   ((cleanup_fn *)get_plugin_function(pl, "disorder_play_cleanup"))(data);
271 }
272
273 /* pause */
274
275 typedef int pause_fn(long *playedp, void *data);
276
277 int 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
284 typedef void resume_fn(void *data);
285
286 void play_resume(const struct plugin *pl, void *data) {
287   (((resume_fn *)get_plugin_function(pl, "disorder_resume_track"))
288    (data));
289 }
290
291 /*
292 Local Variables:
293 c-basic-offset:2
294 comment-column:40
295 End:
296 */