1 /* -*- mode: c; c-file-style: "gnu" -*-
2 * ccze-plugin.c -- Plugin interface for CCZE.
3 * Copyright (C) 2002, 2003 Gergely Nagy <algernon@bonehunter.rulez.org>
4 *
5 * This file is part of ccze.
6 *
7 * ccze is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * ccze is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include <sys/types.h>
23 #include <ccze.h>
24 #include <dirent.h>
25 #include <dlfcn.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30
31 #include "ccze-private.h"
32
33 static ccze_plugin_t **plugins;
34 static size_t plugins_alloc, plugins_len;
35 static ccze_plugin_t **plugin_args;
36 static size_t plugin_args_alloc, plugin_args_len;
37 static char *plugin_running = NULL;
38
39 static ccze_plugin_t *
_ccze_plugin_find(const char * name)40 _ccze_plugin_find (const char *name)
41 {
42 size_t i;
43
44 for (i = 0; i < plugins_len; i++)
45 {
46 if (!strcmp (plugins[i]->name, name))
47 return plugins[i];
48 }
49 return NULL;
50 }
51
52 static int
_ccze_plugin_loaded(const char * name)53 _ccze_plugin_loaded (const char *name)
54 {
55 if (_ccze_plugin_find (name))
56 return 1;
57
58 return 0;
59 }
60
61 static int
_ccze_plugin_allow(const char * name)62 _ccze_plugin_allow (const char *name)
63 {
64 int i = 0;
65 int rval = 0;
66
67 if (_ccze_plugin_loaded (name))
68 return 0;
69 if (ccze_config.pluginlist_len == 0)
70 return 1;
71
72 while (i < ccze_config.pluginlist_len)
73 {
74 if (!strcmp (ccze_config.pluginlist[i], name))
75 {
76 rval = 1;
77 break;
78 }
79 i++;
80 }
81
82 return rval;
83 }
84
85 void
ccze_plugin_add(ccze_plugin_t * plugin)86 ccze_plugin_add (ccze_plugin_t *plugin)
87 {
88 if (!_ccze_plugin_allow (plugin->name))
89 return;
90
91 plugins[plugins_len] = plugin;
92 plugins_len++;
93 if (plugins_len >= plugins_alloc)
94 {
95 plugins_alloc *= 2;
96 plugins = (ccze_plugin_t **)ccze_realloc
97 (plugins, plugins_alloc * sizeof (ccze_plugin_t *));
98 }
99 }
100
101 void
ccze_plugin_init(void)102 ccze_plugin_init (void)
103 {
104 plugins_alloc = 10;
105 plugins_len = 0;
106 plugins = (ccze_plugin_t **)ccze_calloc (plugins_alloc,
107 sizeof (ccze_plugin_t *));
108 }
109
110 void
ccze_plugin_argv_init(void)111 ccze_plugin_argv_init (void)
112 {
113 plugin_args_alloc = 10;
114 plugin_args_len = 0;
115 plugin_args = (ccze_plugin_t **)ccze_calloc (plugin_args_alloc,
116 sizeof (ccze_plugin_t *));
117 }
118
119 static void
_ccze_plugin_load(const char * name,const char * path,int recurse)120 _ccze_plugin_load (const char *name, const char *path, int recurse)
121 {
122 ccze_plugin_t *plugin;
123 char *tmp, *n;
124 void *dlhandle;
125 char **pluginlist = NULL;
126 int bailout = 0;
127
128 if (_ccze_plugin_loaded (name))
129 return;
130
131 dlhandle = dlopen (path, RTLD_LAZY);
132 if (dlerror () || !dlhandle)
133 return;
134
135 asprintf (&tmp, "ccze_%s_info", name);
136 plugin = (ccze_plugin_t *)dlsym (dlhandle, tmp);
137 free (tmp);
138 if (dlerror () || !plugin)
139 {
140 if (!plugin)
141 {
142 n = (char *)dlsym (dlhandle, "ccze_default_plugin");
143 asprintf (&tmp, "ccze_%s_info", n);
144 plugin = (ccze_plugin_t *)dlsym (dlhandle, tmp);
145 free (tmp);
146 if (!plugin)
147 bailout = 1;
148 else
149 plugin->name = strdup (name);
150 }
151 else
152 {
153 dlclose (dlhandle);
154 return;
155 }
156 }
157 if (!bailout)
158 {
159 if (plugin->abi_version != CCZE_ABI_VERSION)
160 {
161 dlclose (dlhandle);
162 return;
163 }
164
165 plugin->dlhandle = dlhandle;
166
167 ccze_plugin_add (plugin);
168 }
169
170 /* If there are more plugins defined in the file, load them all! */
171 if (recurse)
172 {
173 pluginlist = (char **)dlsym (dlhandle, "ccze_plugin_list");
174 if (pluginlist)
175 {
176 int i = 0;
177
178 while (pluginlist[i])
179 {
180 if (!_ccze_plugin_loaded (pluginlist[i]))
181 _ccze_plugin_load (pluginlist[i], path, 0);
182 i++;
183 }
184 }
185 }
186 }
187
188 void
ccze_plugin_load(const char * name)189 ccze_plugin_load (const char *name)
190 {
191 char *home;
192 char *path;
193
194 if ((home = getenv ("HOME")) != NULL)
195 {
196 asprintf (&path, "%s/.ccze/%s.so", home, name);
197 if (access (path, F_OK))
198 {
199 free (path);
200 asprintf (&path, PKGLIBDIR "/%s.so", name);
201 }
202 }
203 else
204 asprintf (&path, PKGLIBDIR "/%s.so", name);
205
206 _ccze_plugin_load (name, path, 1);
207 free (path);
208 }
209
210 static int
_ccze_plugin_select(const struct dirent * de)211 _ccze_plugin_select (const struct dirent *de)
212 {
213 if (strstr (de->d_name, ".so"))
214 return 1;
215 return 0;
216 }
217
218 static void
_ccze_plugin_load_set(struct dirent *** namelist,int nn,const char * base)219 _ccze_plugin_load_set (struct dirent ***namelist, int nn, const char *base)
220 {
221 int m, n = nn;
222
223 m = 0;
224 while (m < n)
225 {
226 char *tmp = strdup ((*namelist)[m]->d_name);
227 char *tmp2 = strstr (tmp, ".so");
228 char *path;
229 tmp2[0] = '\0';
230
231 if (!_ccze_plugin_loaded (tmp))
232 {
233 asprintf (&path, "%s/%s.so", base, tmp);
234 _ccze_plugin_load (tmp, path, 1);
235 free (path);
236 }
237 free (tmp);
238 free ((*namelist)[m]);
239 m++;
240 }
241 free (*namelist);
242 }
243
244 void
ccze_plugin_load_all(void)245 ccze_plugin_load_all (void)
246 {
247 struct dirent **namelist;
248 int n;
249 char *homeplugs, *home;
250
251 if ((home = getenv ("HOME")) != NULL)
252 {
253 asprintf (&homeplugs, "%s/.ccze", home);
254 n = scandir (homeplugs, &namelist, _ccze_plugin_select, alphasort);
255 if (n != -1)
256 _ccze_plugin_load_set (&namelist, n, homeplugs);
257 free (homeplugs);
258 }
259
260 n = scandir (PKGLIBDIR, &namelist, _ccze_plugin_select, alphasort);
261 if (n != -1)
262 _ccze_plugin_load_set (&namelist, n, PKGLIBDIR);
263 }
264
265 void
ccze_plugin_finalise(void)266 ccze_plugin_finalise (void)
267 {
268 plugins[plugins_len] = NULL;
269 }
270
271 ccze_plugin_t **
ccze_plugins(void)272 ccze_plugins (void)
273 {
274 return plugins;
275 }
276
277 void
ccze_plugin_setup(void)278 ccze_plugin_setup (void)
279 {
280 size_t i;
281
282 for (i = 0; i < plugins_len; i++)
283 {
284 if (plugins[i])
285 {
286 plugin_running = plugins[i]->name;
287 (*(plugins[i]->startup))();
288 }
289 }
290 plugin_running = NULL;
291 }
292
293 void
ccze_plugin_shutdown(void)294 ccze_plugin_shutdown (void)
295 {
296 size_t i;
297
298 for (i = 0; i < plugins_len; i++)
299 {
300 if (plugins[i])
301 {
302 plugin_running = plugins[i]->name;
303 (*(plugins[i]->shutdown)) ();
304 free (plugins[i]->argv);
305 if (plugins[i]->dlhandle)
306 dlclose (plugins[i]->dlhandle);
307 }
308 }
309
310 plugin_running = NULL;
311 free (plugins);
312 }
313
314 void
ccze_plugin_run(ccze_plugin_t ** pluginset,char * subject,size_t subjlen,char ** rest,ccze_plugin_type_t type,int * handled,int * status)315 ccze_plugin_run (ccze_plugin_t **pluginset, char *subject, size_t subjlen,
316 char **rest, ccze_plugin_type_t type, int *handled,
317 int *status)
318 {
319 int i = 0;
320
321 while (pluginset[i])
322 {
323 if (pluginset[i]->type == type ||
324 pluginset[i]->type == CCZE_PLUGIN_TYPE_ANY)
325 {
326 plugin_running = pluginset[i]->name;
327 if ((*handled = (*(pluginset[i]->handler))
328 (subject, subjlen, rest)) != 0)
329 {
330 *status = *handled;
331 break;
332 }
333 }
334 i++;
335 }
336 plugin_running = NULL;
337 }
338
339 char **
ccze_plugin_argv_get(const char * name)340 ccze_plugin_argv_get (const char *name)
341 {
342 ccze_plugin_t *p = _ccze_plugin_find (name);
343
344 if (!p)
345 return NULL;
346 return p->argv;
347 }
348
349 int
ccze_plugin_argv_set(const char * name,const char * args)350 ccze_plugin_argv_set (const char *name, const char *args)
351 {
352 ccze_plugin_t *p = NULL;
353 size_t i, j = 1;
354 char *args_copy, *arg;
355
356 if (!args || !name)
357 return -1;
358
359 for (i = 0; i < plugin_args_len; i++)
360 {
361 if (!strcmp (plugin_args[i]->name, name))
362 p = plugin_args[i];
363 }
364
365 if (p)
366 {
367 free (p->argv);
368 p->argv = NULL;
369 }
370 else
371 {
372 p = (ccze_plugin_t *)ccze_malloc (sizeof (ccze_plugin_t));
373 p->name = strdup (name);
374 p->argv = NULL;
375 i = plugin_args_len++;
376 if (plugin_args_len >= plugin_args_alloc)
377 {
378 plugin_args_alloc *= 2;
379 plugin_args = (ccze_plugin_t **)ccze_realloc
380 (plugin_args, plugin_args_alloc * sizeof (ccze_plugin_t *));
381 }
382 }
383
384 args_copy = strdup (args);
385 arg = strtok (args_copy, " \t\n");
386 do
387 {
388 p->argv = (char **)ccze_realloc (p->argv, (j + 1) * sizeof (char *));
389 p->argv[j++] = strdup (arg);
390 } while ((arg = strtok (NULL, " \t\n")) != NULL);
391 p->argv = (char **)ccze_realloc (p->argv, (j + 1) * sizeof (char *));
392 p->argv[j] = NULL;
393 p->argv[0] = strdup (name);
394 plugin_args[i] = p;
395 free (args_copy);
396
397 return 1;
398 }
399
400 void
ccze_plugin_argv_finalise(void)401 ccze_plugin_argv_finalise (void)
402 {
403 ccze_plugin_t *p;
404 size_t i;
405
406 for (i = 0; i < plugin_args_len; i++)
407 {
408 p = _ccze_plugin_find (plugin_args[i]->name);
409 if (p)
410 p->argv = plugin_args[i]->argv;
411 free (plugin_args[i]);
412 }
413 free (plugin_args);
414 }
415
416 const char *
ccze_plugin_name_get(void)417 ccze_plugin_name_get (void)
418 {
419 return plugin_running;
420 }
421
422 int
ccze_plugin_list_fancy(void)423 ccze_plugin_list_fancy (void)
424 {
425 size_t i;
426
427 printf ("Available plugins:\n\n");
428 printf ("%-10s| %-8s| %s\n", "Name", "Type", "Description");
429 printf ("------------------------------------------------------------\n");
430
431 for (i = 0; i < plugins_len; i++)
432 {
433 if (plugins[i])
434 {
435 char *type = "Unknown";
436
437 switch (plugins[i]->type)
438 {
439 case CCZE_PLUGIN_TYPE_FULL:
440 type = "Full";
441 break;
442 case CCZE_PLUGIN_TYPE_PARTIAL:
443 type = "Partial";
444 break;
445 case CCZE_PLUGIN_TYPE_ANY:
446 type = "Any";
447 break;
448 }
449 printf ("%-10s| %-8s| %s\n", plugins[i]->name, type,
450 (plugins[i]->desc) ? plugins[i]->desc : "Undocumented.");
451 }
452 }
453 plugin_running = NULL;
454
455 return 0;
456 }
457