Index: plugins/roard/protocol-gopher.c
===================================================================
--- plugins/roard/protocol-gopher.c	(revision 4706)
+++ plugins/roard/protocol-gopher.c	(revision 4707)
@@ -35,9 +35,13 @@
 
 static int scb_status_txt (int client, struct roar_vio_calls * vio, const char * selector, char ** text);
+static int scb_clients    (int client, struct roar_vio_calls * vio, const char * selector, char ** text);
+static int scb_streams    (int client, struct roar_vio_calls * vio, const char * selector, char ** text);
 
 static struct roar_gopher_menu_item g_gopher_root_menu[] = {
  {.type = _INFO, .name = "roard Root Menu"},
  {.type = _FILE, .name = "Server Info",   .selector = "/info.txt",   .host = NULL, .port = 0},
- {.type = _FILE, .name = "Server Status", .selector = "/status.txt", .host = NULL, .port = 0}
+ {.type = _FILE, .name = "Server Status", .selector = "/status.txt", .host = NULL, .port = 0},
+ {.type = _DIR,  .name = "Clients",       .selector = "/clients/",   .host = NULL, .port = 0},
+ {.type = _DIR,  .name = "Streams",       .selector = "/streams/",   .host = NULL, .port = 0},
 };
 
@@ -61,6 +65,11 @@
  },
  {.selector = "/info.txt",   .type = _FILE, .text = "Some\nText.", .cb = NULL},
- {.selector = "/status.txt", .type = _FILE, .cb = scb_status_txt}
+ {.selector = "/status.txt", .type = _FILE, .cb = scb_status_txt},
+ {.selector = "/clients/",   .type = _DIR,  .cb = scb_clients},
+ {.selector = "/streams/",   .type = _DIR,  .cb = scb_streams}
 };
+
+static int send_menu (int client, struct roar_gopher_menu * menu, struct roar_vio_calls * vio);
+static int send_text (int client, const char * text, struct roar_vio_calls * vio);
 
 
@@ -99,4 +108,111 @@
 }
 
+static int scb_clients    (int client, struct roar_vio_calls * vio, const char * selector, char ** text) {
+ struct roar_gopher_menu_item items[ROAR_CLIENTS_MAX];
+ struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
+ struct roar_gopher_menu_item * item;
+ struct roar_client_server * cs;
+ struct roar_client        * c;
+ const size_t len = 80;
+ char * d;
+ size_t i;
+ int ret;
+
+ memset(items, 0, sizeof(items));
+
+ for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
+  if ( (c = ROAR_CLIENT((cs = g_clients[i]))) != NULL ) {
+   item = &(items[menu.items_len++]);
+   item->type = _DIR;
+   d = roar_mm_malloc(len);
+   if ( d == NULL ) {
+    menu.items_len--;
+    continue;
+   }
+   if ( c->name != NULL && c->name[0] != 0 ) {
+    snprintf(d, len, "Client %i: %s", (int)i, c->name);
+   } else {
+    snprintf(d, len, "Client %i", (int)i);
+   }
+   item->name = d;
+
+   d = roar_mm_malloc(len);
+   if ( d == NULL ) {
+    if ( item->name != NULL )
+     roar_mm_free((void*)item->name);
+    menu.items_len--;
+    continue;
+   }
+
+   snprintf(d, len, "/clients/%i/", (int)i);
+   item->selector = d;
+  }
+ }
+
+ ret = send_menu(client, &menu, vio);
+
+ for (i = 0; i < menu.items_len; i++) {
+  if ( items[i].name != NULL )
+   roar_mm_free((void*)items[i].name);
+  if ( items[i].selector != NULL )
+   roar_mm_free((void*)items[i].selector);
+ }
+
+ return ret;
+}
+
+static int scb_streams    (int client, struct roar_vio_calls * vio, const char * selector, char ** text) {
+ struct roar_gopher_menu_item items[ROAR_STREAMS_MAX];
+ struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
+ struct roar_gopher_menu_item * item;
+ struct roar_stream_server * ss;
+ struct roar_stream        * s;
+ const size_t len = 80;
+ char * d;
+ size_t i;
+ int ret;
+
+ memset(items, 0, sizeof(items));
+
+ for (i = 0; i < ROAR_STREAMS_MAX; i++) {
+  if ( (s = ROAR_STREAM((ss = g_streams[i]))) != NULL ) {
+   item = &(items[menu.items_len++]);
+   item->type = _DIR;
+   d = roar_mm_malloc(len);
+   if ( d == NULL ) {
+    menu.items_len--;
+    continue;
+   }
+   if ( ss->name != NULL && ss->name[0] != 0 ) {
+    snprintf(d, len, "Stream %i: %s", (int)i, ss->name);
+   } else {
+    snprintf(d, len, "Stream %i", (int)i);
+   }
+   item->name = d;
+
+   d = roar_mm_malloc(len);
+   if ( d == NULL ) {
+    if ( item->name != NULL )
+     roar_mm_free((void*)item->name);
+    menu.items_len--;
+    continue;
+   }
+
+   snprintf(d, len, "/streams/%i/", (int)i);
+   item->selector = d;
+  }
+ }
+
+ ret = send_menu(client, &menu, vio);
+
+ for (i = 0; i < menu.items_len; i++) {
+  if ( items[i].name != NULL )
+   roar_mm_free((void*)items[i].name);
+  if ( items[i].selector != NULL )
+   roar_mm_free((void*)items[i].selector);
+ }
+
+ return ret;
+}
 
 // other code:
