Index: ChangeLog
===================================================================
--- ChangeLog	(revision 5272)
+++ ChangeLog	(revision 5275)
@@ -5,4 +5,5 @@
 	* Removed old functions from API (Closes: #186, See: #130)
 	* Removed old roarclients (See: #130)
+	* Improved plugin loader a lot (Closes: #190)
 
 v. 0.4 - Fri Nov 11 2011 20:12 CET
Index: doc/man1/roard.1
===================================================================
--- doc/man1/roard.1	(revision 5159)
+++ doc/man1/roard.1	(revision 5275)
@@ -152,6 +152,11 @@
 .SH "PLUGINS"
 .TP
-\fB--plugin-load\fR
+\fB--plugin-load FILENAME\fR
 Load the given plugin.
+
+.TP
+\fB--plugin-args ARGS\fR
+Arguments for the plugin.
+(must be given before the --plugin-load).
 
 .SH "SECURITY"
Index: include/libroar/roardl.h
===================================================================
--- include/libroar/roardl.h	(revision 4708)
+++ include/libroar/roardl.h	(revision 5275)
@@ -57,8 +57,9 @@
 #define ROAR_DL_FN_PROTO               11
 //#define ROAR_DL_FN_               9
-#define ROAR_DL_FN_MAX                 16
+#define ROAR_DL_FN_MAX                 24
 
-#define ROAR_DL_LIBPARA_VERSION         0
-#define ROAR_DL_LIBINST_VERSION         0
+#define ROAR_DL_LIBPARA_VERSION         1
+#define ROAR_DL_LIBNAME_VERSION         0
+#define ROAR_DL_LIBINST_VERSION         1
 
 #define ROAR_DL_PLUGIN(lib) struct roar_dl_libraryinst *                                          \
@@ -74,4 +75,5 @@
                                      static int _inited = 0;                                      \
                                      static struct roar_dl_libraryinst lib;                       \
+                                     static struct roar_dl_libraryname libname;                   \
                                      (void)para;                                                  \
                                      if ( _inited )                                               \
@@ -80,4 +82,9 @@
                                      lib.version = ROAR_DL_LIBINST_VERSION;                       \
                                      lib.len     = sizeof(lib);                                   \
+                                     memset(&libname, 0, sizeof(libname));                        \
+                                     libname.version = ROAR_DL_LIBNAME_VERSION;                   \
+                                     libname.len     = sizeof(libname);                           \
+                                     libname.name = #xlib;                                        \
+                                     lib.libname  = &libname;                                     \
                                      do
 
@@ -87,10 +94,50 @@
                                    }
 
+#define ROAR_DL_PLUGIN_ABORT_LOADING(err) roar_err_set((err)); return NULL
+#define ROAR_DL_PLUGIN_CHECK_VERSIONS(app,abi) if ( roar_dl_para_check_version(para, (app), (abi)) == -1 ) return NULL
 #define ROAR_DL_PLUGIN_REG(fn, funcptr) (lib.func[(fn)] = (funcptr))
 #define ROAR_DL_PLUGIN_REG_UNLOAD(func) (lib.unload = (func))
 
 struct roar_dl_librarypara {
- int version;
- size_t len;
+ int version;               // version of this struct type (must be ROAR_DL_LIBPARA_VERSION)
+ size_t len;                // Length of this struct type (must be sizeof(struct roar_dl_librarypara)
+
+ size_t refc;               // Reference counter.
+
+ size_t argc;               // number of elements in argv
+ struct roar_keyval * argv; // Parameter for the plugin
+ void * args_store;         // Storage area for argv's data.
+                            // If not NULL this and argv will be freed.
+                            // If NULL argv will be left untouched.
+
+ void * binargv;            // A pointer with binary data arguments.
+                            // This can be used to pass any non-string data to
+                            // the plugin. Normally this is NULL or the pointer
+                            // to a struct with members of whatever is needed.
+
+ const char * appname;      // application name in common format:
+                            // Product/Version <VendorID/VendorName> (comments)
+                            // Version and comment are optional and should be avoided.
+                            // When no vendor ID is registered use <VendorName>.
+                            // The VendorName MUST NOT contain a slash and SHOULD
+                            // be as unique as possible.
+                            // Examples: roard <0/RoarAudio>, MyAPP <myapp.org>,
+                            //           AnAPP <Musterman GbR>
+ const char * abiversion;   // The ABI version. For libraries this should be the SONAME.
+                            // For applications this should be the version of the release
+                            // which introduced the current ABI.
+                            // Examples: libroar2, 0.5.1
+};
+
+struct roar_dl_libraryname {
+ int      version;
+ size_t   len;
+ const char * name;        //Format: shortname
+ const char * libversion;  //Format: Product/Version <VendorID/VendorName> (comments)
+ const char * description; //Free form.
+ const char * contact;     //Format: first ["']nick["'] last (comment) <email>/OpenPGPkey/Phone/Room
+ const char * authors;     //Other authors as free form.
+ const char * license;     //Format: LicenseName-Version (options)
+                           //Examples: GPL-3.0, LGPL-2.1, LGPL-3.0 (or later).
 };
 
@@ -100,24 +147,28 @@
  int    (*unload)(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib);
  int    (*func[ROAR_DL_FN_MAX])(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib);
+ struct roar_dl_libraryname * libname;
 };
 
-struct roar_dl_lhandle {
- struct roar_dl_librarypara * para;
- struct roar_dl_libraryinst * lib;
-#if defined(ROAR_HAVE_LIBDL)
- void * handle;
-#else
- char dummy[8];
-#endif
-};
+struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv,
+                                              const char * appname, const char * abiversion);
+int roar_dl_para_ref                    (struct roar_dl_librarypara * para);
+int roar_dl_para_unref                  (struct roar_dl_librarypara * para);
+int roar_dl_para_check_version          (struct roar_dl_librarypara * para,
+                                         const char * appname, const char * abiversion);
 
-struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags, int ra_init);
-int                      roar_dl_close(struct roar_dl_lhandle * lhandle);
+struct roar_dl_lhandle * roar_dl_open   (const char * filename, int flags,
+                                         int ra_init, struct roar_dl_librarypara * para);
+int                      roar_dl_close  (struct roar_dl_lhandle * lhandle);
 
-void                   * roar_dl_getsym(struct roar_dl_lhandle * lhandle, const char * sym, int type);
+void                   * roar_dl_getsym (struct roar_dl_lhandle * lhandle, const char * sym, int type);
 
-int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle, const char * prefix);
+int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
+                                         const char * prefix,
+                                         struct roar_dl_librarypara * para);
 
-char *                   roar_dl_errstr(struct roar_dl_lhandle * lhandle);
+const char *             roar_dl_errstr (struct roar_dl_lhandle * lhandle);
+
+struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle);
+const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle);
 
 #endif
Index: libroar/roardl.c
===================================================================
--- libroar/roardl.c	(revision 5270)
+++ libroar/roardl.c	(revision 5275)
@@ -40,4 +40,122 @@
 #endif
 
+struct roar_dl_lhandle {
+ struct roar_dl_librarypara * para;
+ struct roar_dl_libraryinst * lib;
+#if defined(ROAR_HAVE_LIBDL)
+ void * handle;
+#endif
+};
+
+
+struct roar_dl_librarypara * roar_dl_para_new(const char * args, void * binargv,
+                                              const char * appname, const char * abiversion) {
+ struct roar_dl_librarypara * ret = roar_mm_malloc(sizeof(struct roar_dl_librarypara));
+ ssize_t argc;
+ int err;
+
+ if ( ret == NULL )
+  return NULL;
+
+ memset(ret, 0, sizeof(struct roar_dl_librarypara));
+
+ ret->version    = ROAR_DL_LIBPARA_VERSION;
+ ret->len        = sizeof(struct roar_dl_librarypara);
+ ret->refc       = 1;
+ ret->argc       = 0;
+ ret->argv       = NULL;
+ ret->args_store = NULL;
+ ret->binargv    = binargv;
+ ret->appname    = appname;
+ ret->abiversion = abiversion;
+
+ if ( args != NULL ) {
+  ret->args_store = roar_mm_strdup(args);
+  if ( ret->args_store == NULL ) {
+   err = roar_error;
+   roar_mm_free(ret);
+   roar_error = err;
+   return NULL;
+  }
+
+  argc = roar_keyval_split(&(ret->argv), ret->args_store, NULL, NULL, 0);
+  if ( argc == -1 ) {
+   err = roar_error;
+   roar_mm_free(ret->args_store);
+   roar_mm_free(ret);
+   roar_error = err;
+   return NULL;
+  }
+
+  ret->argc = argc;
+ }
+
+ return ret;
+}
+
+int roar_dl_para_ref                    (struct roar_dl_librarypara * para) {
+ if ( para == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ para->refc++;
+
+ return 0;
+}
+
+int roar_dl_para_unref                  (struct roar_dl_librarypara * para) {
+ if ( para == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ para->refc--;
+
+ if ( para->refc == 0 ) {
+  if ( para->args_store != NULL ) {
+   roar_mm_free(para->args_store);
+   roar_mm_free(para->argv);
+  }
+  roar_mm_free(para);
+ }
+
+ return 0;
+}
+int roar_dl_para_check_version          (struct roar_dl_librarypara * para,
+                                         const char * appname, const char * abiversion) {
+ if ( para == NULL ) {
+  roar_err_set(ROAR_ERROR_FAULT);
+  return -1;
+ }
+
+ // check if both appnames are NULL or non-NULL.
+ if ( (para->appname == NULL && appname != NULL) || (para->appname != NULL && appname == NULL) ) {
+  roar_err_set(ROAR_ERROR_BADVERSION);
+  return -1;
+ }
+
+ // check if the appname matches if given.
+ if ( para->appname != NULL && !!strcmp(para->appname, appname) ) {
+  roar_err_set(ROAR_ERROR_BADVERSION);
+  return -1;
+ }
+
+ // check if both ABI versions are NULL or non-NULL.
+ if ( (para->abiversion == NULL && abiversion != NULL) || (para->abiversion != NULL && abiversion == NULL) ) {
+  roar_err_set(ROAR_ERROR_BADVERSION);
+  return -1;
+ }
+
+ // check if the ABI versions matches if given.
+ if ( para->abiversion != NULL && !!strcmp(para->abiversion, abiversion) ) {
+  roar_err_set(ROAR_ERROR_BADVERSION);
+  return -1;
+ }
+
+ return 0;
+}
+
+
 #if defined(ROAR_HAVE_LIBDL)
 static void * _roardl2ldl (struct roar_dl_lhandle * lhandle) {
@@ -52,11 +170,15 @@
 #endif
 
-struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags, int ra_init) {
+struct roar_dl_lhandle * roar_dl_open(const char * filename, int flags,
+                                      int ra_init, struct roar_dl_librarypara * para) {
  struct roar_dl_lhandle * ret = NULL;
+ int err;
 
  // early errors just return.
 
- if ( flags != ROAR_DL_FLAG_DEFAUTS )
-  return NULL;
+ if ( flags != ROAR_DL_FLAG_DEFAUTS ) {
+  roar_err_set(ROAR_ERROR_NOTSUP);
+  return NULL;
+ }
 
  if ( (ret = roar_mm_malloc(sizeof(struct roar_dl_lhandle))) == NULL )
@@ -80,13 +202,25 @@
 #else
  roar_mm_free(ret);
+ roar_err_set(ROAR_ERROR_NOSYS);
  return NULL;
 #endif
 
- if ( ret == NULL )
-  return NULL;
+ ret->para = para;
 
  if ( ra_init ) {
-  roar_dl_ra_init(ret, NULL);
- }
+  if ( roar_dl_ra_init(ret, NULL, para) == -1 ) {
+   err = roar_error;
+   ROAR_WARN("roar_dl_open(filename='%s', flags=%i, ra_init=%i, para=%p): Can not init RA lib: %s", filename, flags, ra_init, para, roar_error2str(err));
+#if defined(ROAR_HAVE_LIBDL)
+   dlclose(ret->handle);
+#endif
+   roar_mm_free(ret);
+   roar_error = err;
+   return NULL;
+  }
+ }
+
+ if ( para != NULL )
+  roar_dl_para_ref(para);
 
  return ret;
@@ -96,8 +230,8 @@
  int ret = -1;
 
- if ( lhandle == ROAR_DL_HANDLE_DEFAULT )
-  return -1;
- if ( lhandle == ROAR_DL_HANDLE_NEXT )
-  return -1;
+ if ( lhandle == ROAR_DL_HANDLE_DEFAULT || lhandle == ROAR_DL_HANDLE_NEXT ) {
+  roar_err_set(ROAR_ERROR_BADFH);
+  return -1;
+ }
 
  if ( lhandle->lib != NULL && lhandle->lib->unload != NULL )
@@ -110,4 +244,7 @@
 #endif
 
+ if ( lhandle->para != NULL )
+  roar_dl_para_unref(lhandle->para);
+
  roar_mm_free(lhandle);
 
@@ -129,10 +266,11 @@
 }
 
-int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle, const char * prefix) {
+int                      roar_dl_ra_init(struct roar_dl_lhandle * lhandle,
+                                         const char * prefix,
+                                         struct roar_dl_librarypara * para) {
 #define _SUFFIX "_roaraudio_library_init"
  char name[80] = _SUFFIX;
  struct roar_dl_libraryinst * (*func)(struct roar_dl_librarypara * para);
  struct roar_dl_libraryinst * lib;
- struct roar_dl_librarypara * para = NULL;
  int i;
 
@@ -141,5 +279,6 @@
    return -1;
  } else {
-  para = lhandle->para;
+  if ( para == NULL )
+   para = lhandle->para;
  }
 
@@ -181,5 +320,5 @@
 }
 
-char *                   roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
+const char * roar_dl_errstr(struct roar_dl_lhandle * lhandle) {
 #if defined(ROAR_HAVE_LIBDL)
  (void)lhandle;
@@ -190,3 +329,49 @@
 }
 
+struct roar_dl_librarypara       * roar_dl_getpara(struct roar_dl_lhandle * lhandle) {
+ if ( (void*)lhandle < (void*)128 ) {
+  roar_err_set(ROAR_ERROR_NOTSUP);
+  return NULL;
+ }
+
+ if ( lhandle->para == NULL ) {
+  roar_err_set(ROAR_ERROR_NOENT);
+  return NULL;
+ }
+
+ if ( roar_dl_para_ref(lhandle->para) == -1 )
+  return NULL;
+
+ return lhandle->para;
+}
+
+const struct roar_dl_libraryname * roar_dl_getlibname(struct roar_dl_lhandle * lhandle) {
+ if ( (void*)lhandle < (void*)128 ) {
+  roar_err_set(ROAR_ERROR_NOTSUP);
+  return NULL;
+ }
+
+ if ( lhandle->lib == NULL ) {
+  roar_err_set(ROAR_ERROR_BADLIB);
+  return NULL;
+ }
+
+ if ( lhandle->lib->libname == NULL ) {
+  roar_err_set(ROAR_ERROR_NOENT);
+  return NULL;
+ }
+
+ if ( lhandle->lib->libname->version != ROAR_DL_LIBNAME_VERSION ) {
+  roar_err_set(ROAR_ERROR_BADVERSION);
+  return NULL;
+ }
+
+ if ( lhandle->lib->libname->len != sizeof(struct roar_dl_libraryname) ) {
+  roar_err_set(ROAR_ERROR_HOLE);
+  return NULL;
+ }
+
+ return lhandle->lib->libname;
+}
+
 //ll
Index: libroar/vio_dstr.c
===================================================================
--- libroar/vio_dstr.c	(revision 5270)
+++ libroar/vio_dstr.c	(revision 5275)
@@ -289,8 +289,8 @@
 
 static void _roar_vio_dstr_init_otherlibs (void) {
- roar_dl_ra_init(ROAR_DL_HANDLE_DEFAULT, "libroardsp");
- roar_dl_ra_init(ROAR_DL_HANDLE_DEFAULT, "libroareio");
- roar_dl_ra_init(ROAR_DL_HANDLE_DEFAULT, "libroarlight");
- roar_dl_ra_init(ROAR_DL_HANDLE_DEFAULT, "libroarmidi");
+ roar_dl_ra_init(ROAR_DL_HANDLE_DEFAULT, "libroardsp",   NULL);
+ roar_dl_ra_init(ROAR_DL_HANDLE_DEFAULT, "libroareio",   NULL);
+ roar_dl_ra_init(ROAR_DL_HANDLE_DEFAULT, "libroarlight", NULL);
+ roar_dl_ra_init(ROAR_DL_HANDLE_DEFAULT, "libroarmidi",  NULL);
 }
 
Index: plugins/roard/listenpty.c
===================================================================
--- plugins/roard/listenpty.c	(revision 5267)
+++ plugins/roard/listenpty.c	(revision 5275)
@@ -59,4 +59,8 @@
 
 ROAR_DL_PLUGIN_START(roard_discard_protocol) {
+ ROARD_DL_CHECK_VERSIONS();
+
+ libname.license = "GPL-3.0";
+
  ROARD_DL_REGFN_SCHED();
 } ROAR_DL_PLUGIN_END
Index: plugins/universal/protocol-daytime.c
===================================================================
--- plugins/universal/protocol-daytime.c	(revision 5193)
+++ plugins/universal/protocol-daytime.c	(revision 5275)
@@ -59,5 +59,5 @@
 
 static struct roard_proto proto[1] = {
- {ROAR_PROTO_DAYTIME, new_client, NULL, NULL, flushed_client}
+ {ROAR_PROTO_DAYTIME, ROAR_SUBSYS_NONE, "The Internet daytime protocol", new_client, NULL, NULL, flushed_client}
 };
 
@@ -65,4 +65,8 @@
 
 ROAR_DL_PLUGIN_START(roard_daytime_protocol) {
+ ROARD_DL_CHECK_VERSIONS();
+
+ libname.license = "GPL-3.0";
+
  ROARD_DL_REGFN_PROTO();
 } ROAR_DL_PLUGIN_END
Index: plugins/universal/protocol-discard.c
===================================================================
--- plugins/universal/protocol-discard.c	(revision 5264)
+++ plugins/universal/protocol-discard.c	(revision 5275)
@@ -42,5 +42,5 @@
 
 static struct roard_proto proto[1] = {
- {ROAR_PROTO_DISCARD, NULL, check_client, NULL, NULL}
+ {ROAR_PROTO_DISCARD, ROAR_SUBSYS_NONE, "Discard all data send to the server", NULL, check_client, NULL, NULL}
 };
 
@@ -48,4 +48,8 @@
 
 ROAR_DL_PLUGIN_START(roard_discard_protocol) {
+ ROARD_DL_CHECK_VERSIONS();
+
+ libname.license = "GPL-3.0"; 
+
  ROARD_DL_REGFN_PROTO();
 } ROAR_DL_PLUGIN_END
Index: plugins/universal/protocol-echo.c
===================================================================
--- plugins/universal/protocol-echo.c	(revision 5193)
+++ plugins/universal/protocol-echo.c	(revision 5275)
@@ -57,5 +57,5 @@
 
 static struct roard_proto proto[1] = {
- {ROAR_PROTO_ECHO, NULL, check_client, NULL, NULL}
+ {ROAR_PROTO_ECHO, ROAR_SUBSYS_NONE, "Send all data send to the server back to the client", NULL, check_client, NULL, NULL}
 };
 
@@ -63,4 +63,8 @@
 
 ROAR_DL_PLUGIN_START(roard_echo_protocol) {
+ ROARD_DL_CHECK_VERSIONS();
+
+ libname.license = "GPL-3.0";
+
  ROARD_DL_REGFN_PROTO();
 } ROAR_DL_PLUGIN_END
Index: roard/clients.c
===================================================================
--- roard/clients.c	(revision 5242)
+++ roard/clients.c	(revision 5275)
@@ -38,14 +38,14 @@
 #ifndef ROAR_WITHOUT_DCOMP_EMUL_ESD
 #ifdef ROAR_HAVE_H_ESD
- {ROAR_PROTO_ESOUND, NULL, emul_esd_check_client, NULL, NULL},
+ {ROAR_PROTO_ESOUND, ROAR_SUBSYS_WAVEFORM, "EsounD emulation", NULL, emul_esd_check_client, NULL, NULL},
 #endif
 #endif
 #ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
- {ROAR_PROTO_RPLAY, NULL, emul_rplay_check_client, NULL, NULL},
+ {ROAR_PROTO_RPLAY, ROAR_SUBSYS_WAVEFORM, "RPlay emulation", NULL, emul_rplay_check_client, NULL, NULL},
 #endif
 #ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
- {ROAR_PROTO_GOPHER, NULL, emul_gopher_check_client, NULL, emul_gopher_flushed_client},
-#endif
- {-1, NULL}
+ {ROAR_PROTO_GOPHER, ROAR_SUBSYS_WAVEFORM, "The Internet Gopher Protocol", NULL, emul_gopher_check_client, NULL, emul_gopher_flushed_client},
+#endif
+ {-1, 0, NULL, NULL, NULL, NULL, NULL}
 };
 
@@ -58,4 +58,9 @@
  for (i = 0; i < ROAR_CLIENTS_MAX; i++)
   g_clients[i] = NULL;
+
+ for (i = 0; g_proto[i].proto != -1; i++);
+
+ for (; i < MAX_PROTOS; i++)
+  g_proto[i].proto = -1;
 
  return 0;
@@ -826,12 +831,104 @@
  memcpy(&(g_proto[i]), proto, sizeof(*g_proto));
 
- i++;
-
- memset(&(g_proto[i]), 0, sizeof(*g_proto));
- g_proto[i].proto = -1;
-
- return 0;
-}
-
+ return 0;
+}
+
+int clients_unregister_proto(int proto) {
+ const size_t len = sizeof(g_proto)/sizeof(*g_proto);
+ size_t i;
+
+ if ( proto < 0 ) {
+  roar_err_set(ROAR_ERROR_RANGE);
+  return -1;
+ }
+
+ for (i = 0; i < len; i++) {
+  if ( g_proto[i].proto == proto ) {
+   memset(&(g_proto[i]), 0, sizeof(*g_proto));
+   g_proto[i].proto = -1;
+   return 0;
+  }
+ }
+
+ roar_err_set(ROAR_ERROR_NOENT);
+ return -1;
+}
+
+void print_protolist        (enum output_format format) {
+ const size_t len = sizeof(g_proto)/sizeof(*g_proto);
+ struct roard_proto * p;
+ char subsys[7] = "      ";
+ size_t i;
+
+ switch (format) {
+  case FORMAT_NATIVE:
+    printf("  Protocol Flag Subsys - Description\n");
+    printf("------------------------------------------------------\n");
+    printf("  roar          WM LRX - RoarAudio native protocol\n");
+#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
+    printf("  simple        WM LRX - PulseAudio simple protocol\n");
+#endif
+#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
+    printf("  rsound        W      - RSound emulation\n");
+#endif
+   break;
+  case FORMAT_WIKI:
+    printf("||=Protocol =||=Flag =||=Subsys =||=Description              =||\n");
+    printf("||roar       ||       ||WM LRX   ||RoarAudio native protocol  ||\n");
+#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
+    printf("||simple     ||       ||WM LRX   ||PulseAudio simple protocol ||\n");
+#endif
+#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
+    printf("||rsound     ||       ||W        ||RSound emulation           ||\n");
+#endif
+   break;
+  case FORMAT_CSV:
+    printf("Protocol,Flag,Subsys,Description\n");
+    printf("roar,,WM LRX,RoarAudio native protocol\n");
+#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
+    printf("simple,,WM LRX,PulseAudio simple protocol\n");
+#endif
+#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
+    printf("rsound,,W,RSound emulation\n");
+#endif
+   break;
+  default:
+    roar_err_set(ROAR_ERROR_NOTSUP);
+    return;
+ }
+
+ for (i = 0; i < len; i++) {
+  p = &(g_proto[i]);
+  if ( p->proto == -1 )
+   continue;
+
+  strncpy(subsys, "      ", 6);
+
+  if ( p->subsystems & ROAR_SUBSYS_WAVEFORM )
+   subsys[0] = 'W';
+  if ( p->subsystems & ROAR_SUBSYS_MIDI )
+   subsys[1] = 'M';
+  if ( p->subsystems & ROAR_SUBSYS_CB )
+   subsys[2] = 'C';
+  if ( p->subsystems & ROAR_SUBSYS_LIGHT )
+   subsys[3] = 'L';
+  if ( p->subsystems & ROAR_SUBSYS_RAW )
+   subsys[4] = 'R';
+  if ( p->subsystems & ROAR_SUBSYS_COMPLEX )
+   subsys[5] = 'X';
+
+  switch (format) {
+   case FORMAT_NATIVE:
+     printf("  %-13s %s - %s\n", roar_proto2str(p->proto), subsys, p->description);
+    break;
+   case FORMAT_WIKI:
+     printf("||%s || ||%s ||%s ||\n", roar_proto2str(p->proto), subsys, p->description);
+    break;
+   case FORMAT_CSV:
+     printf("%s,,%s,%s\n", roar_proto2str(p->proto), subsys, p->description);
+    break;
+  }
+ }
+}
 
 int client_stream_exec   (int client, int stream) {
Index: roard/include/client.h
===================================================================
--- roard/include/client.h	(revision 5192)
+++ roard/include/client.h	(revision 5275)
@@ -76,4 +76,6 @@
 struct roard_proto {
  int proto;
+ int subsystems;
+ const char * description;
  int (*new_client)(int client, struct roar_vio_calls * vio, struct roard_listen * lsock);
  int (*check_client)(int client, struct roar_vio_calls * vio);
@@ -114,5 +116,7 @@
 
 // proto support
-int clients_register_proto(struct roard_proto * proto);
+int clients_register_proto  (struct roard_proto * proto);
+int clients_unregister_proto(int proto);
+void print_protolist        (enum output_format format);
 
 // stream functions
Index: roard/include/plugins.h
===================================================================
--- roard/include/plugins.h	(revision 5266)
+++ roard/include/plugins.h	(revision 5275)
@@ -29,4 +29,7 @@
 #include <roaraudio.h>
 
+#define ROARD_DL_APPNAME    "roard <0/RoarAudio>"
+#define ROARD_DL_ABIVERSION NULL
+
 struct roard_plugins_sched {
  int (*init)(void);
@@ -40,5 +43,5 @@
 int plugins_update   (void);
 
-int plugins_load     (const char * filename);
+int plugins_load     (const char * filename, const char * args);
 
 int plugins_reg_sched(struct roard_plugins_sched * sched);
@@ -62,4 +65,5 @@
  ROARD_DL_REG__UNI_POST
 
+// Register Scheduler callbacks:
 #define ROARD_DL_REGFN_SCHED() ROAR_DL_PLUGIN_REG(ROAR_DL_FN_ROARDSCHED, __reg_sched)
 
@@ -70,5 +74,9 @@
  ROARD_DL_REG__UNI_POST
 
+// Register Protocol callbacks:
 #define ROARD_DL_REGFN_PROTO() ROAR_DL_PLUGIN_REG(ROAR_DL_FN_PROTO, __reg_proto)
+
+// Check version:
+#define ROARD_DL_CHECK_VERSIONS() ROAR_DL_PLUGIN_CHECK_VERSIONS(ROARD_DL_APPNAME, ROARD_DL_ABIVERSION)
 
 #endif
Index: roard/plugins.c
===================================================================
--- roard/plugins.c	(revision 4708)
+++ roard/plugins.c	(revision 5275)
@@ -31,4 +31,5 @@
  struct roar_dl_lhandle     * lhandle;
  struct roard_plugins_sched * sched;
+ int protocols[MAX_PROTOS];
 } g_plugins[MAX_PLUGINS];
 static struct _roard_plugin * _pp = NULL;
@@ -53,4 +54,22 @@
 }
 
+static void inline plugins_delete(struct _roard_plugin * plugin) {
+ int i;
+
+ if ( plugin->sched != NULL )
+  if ( plugin->sched->free != NULL )
+   plugin->sched->free();
+
+ for (i = 0; i < MAX_PROTOS; i++) {
+  if ( plugin->protocols[i] != -1 ) {
+   clients_unregister_proto(plugin->protocols[i]);
+  }
+ }
+
+ roar_dl_close(plugin->lhandle);
+ memset(plugin, 0, sizeof(struct _roard_plugin));
+ plugin->lhandle = NULL;
+}
+
 int plugins_init  (void) {
  int i;
@@ -62,5 +81,9 @@
    _pp->sched = NULL;
 
-   roar_dl_ra_init(g_plugins[i].lhandle, NULL);
+   if ( roar_dl_ra_init(g_plugins[i].lhandle, NULL, NULL) == -1 ) {
+    ROAR_WARN("plugins_init(void): Can not RA init lib at %p: %s", g_plugins[i].lhandle, roar_error2str(roar_error));
+    plugins_delete(&(g_plugins[i]));
+    continue;
+   }
 
    if ( g_plugins[i].sched != NULL )
@@ -80,9 +103,5 @@
  for (i = 0; i < MAX_PLUGINS; i++) {
   if ( g_plugins[i].lhandle != NULL ) {
-   if ( g_plugins[i].sched != NULL )
-    if ( g_plugins[i].sched->free != NULL )
-     g_plugins[i].sched->free();
-
-   roar_dl_close(g_plugins[i].lhandle);
+   plugins_delete(&(g_plugins[i]));
   }
  }
@@ -105,11 +124,23 @@
 }
 
-int plugins_load  (const char * filename) {
+int plugins_load  (const char * filename, const char * args) {
  struct _roard_plugin * next = _find_free();
+ struct roar_dl_librarypara * para;
+ int i;
 
  if ( next == NULL )
   return -1;
 
- next->lhandle = roar_dl_open(filename, -1, 0 /* we delay this until plugins_init() */);
+ for (i = 0; i < MAX_PROTOS; i++)
+  next->protocols[i] = -1;
+
+ if ( (para = roar_dl_para_new(args, NULL, ROARD_DL_APPNAME, ROARD_DL_ABIVERSION)) == NULL ) {
+  ROAR_WARN("Can not load plugin (allocate para set): %s: %s", filename, roar_error2str(roar_error));
+  return -1;
+ }
+
+ next->lhandle = roar_dl_open(filename, ROAR_DL_FLAG_DEFAUTS, 0 /* we delay this until plugins_init() */, para);
+ roar_dl_para_unref(para);
+
  if ( next->lhandle == NULL ) {
   ROAR_ERR("plugins_load(filename='%s'): can not load plugin: %s", filename, roar_dl_errstr(NULL));
@@ -130,6 +161,20 @@
 
 int plugins_reg_proto(struct roard_proto         * proto) {
+ int i;
+
  if ( _pp == NULL )
   return -1;
+
+ for (i = 0; i < MAX_PROTOS; i++) {
+  if ( _pp->protocols[i] == -1 ) {
+   _pp->protocols[i] = proto->proto;
+   break;
+  }
+ }
+
+ if ( i == MAX_PROTOS ) {
+  roar_err_set(ROAR_ERROR_NOMEM);
+  return -1;
+ }
 
  return clients_register_proto(proto);
Index: roard/roard.c
===================================================================
--- roard/roard.c	(revision 5257)
+++ roard/roard.c	(revision 5275)
@@ -260,4 +260,6 @@
  printf(
         " --plugin-load FILE    - Load plugin FILE\n"
+        " --plugin-args ARGS    - Arguments for the plugin\n"
+        "                         (must be given before the --plugin-load)\n"
        );
 
@@ -417,25 +419,4 @@
 // printf("\n Options:\n\n");
  printf("\n");
-}
-
-static void list_proto (void) {
- printf("  Protocol Flag Subsys - Description\n");
- printf("------------------------------------------------------\n");
- printf("  roar          WM LRX - RoarAudio native protocol\n");
-#if !defined(ROAR_WITHOUT_DCOMP_EMUL_ESD) && defined(ROAR_HAVE_H_ESD)
- printf("  esd           W      - EsounD emulation\n");
-#endif
-#ifndef ROAR_WITHOUT_DCOMP_EMUL_SIMPLE
- printf("  simple        WM LRX - PulseAudio simple protocol\n");
-#endif
-#ifndef ROAR_WITHOUT_DCOMP_EMUL_RSOUND
- printf("  rsound        W      - RSound emulation\n");
-#endif
-#ifndef ROAR_WITHOUT_DCOMP_EMUL_RPLAY
- printf("  rplay         W      - RPlay emulation\n");
-#endif
-#ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
- printf("  gopher               - The Internet Gopher Protocol\n");
-#endif
 }
 
@@ -1380,4 +1361,5 @@
  int    sysclocksync = 0;
 // char * server = ROAR_DEFAULT_SOCK_GLOBAL;
+ const char * plugin_args = NULL;
 #ifdef ROAR_SUPPORT_LISTEN
  int    port       = ROAR_DEFAULT_PORT;
@@ -1701,7 +1683,11 @@
   } else if ( strcmp(k, "--plugin-load") == 0 ) {
    _CKHAVEARGS(1);
-   if ( plugins_load(argv[++i]) == -1 ) {
+   if ( plugins_load(argv[++i], plugin_args) == -1 ) {
     ROAR_ERR("Can not load plugin");
    }
+   plugin_args = NULL;
+  } else if ( strcmp(k, "--plugin-args") == 0 ) {
+   _CKHAVEARGS(1);
+   plugin_args = argv[++i];
 
   } else if ( strcmp(k, "--guest-acclev") == 0 ) {
@@ -2140,5 +2126,5 @@
 
   } else if ( strcmp(k, "--list-proto") == 0 ) {
-   list_proto();
+   print_protolist(print_format);
    return 0;
 
