source: roaraudio/plugins/roard/protocol-gopher.c @ 5741:edecee88ed39

Last change on this file since 5741:edecee88ed39 was 5741:edecee88ed39, checked in by phi, 11 years ago

some general improvements to move away from roard a bit more

File size: 24.0 KB
RevLine 
[4699]1//emul_gopher.c:
2
3/*
[5381]4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2012
[4699]5 *
6 *  This file is part of roard a part of RoarAudio,
7 *  a cross-platform sound system for both, home and professional use.
8 *  See README for details.
9 *
10 *  This file is free software; you can redistribute it and/or modify
11 *  it under the terms of the GNU General Public License version 3
12 *  as published by the Free Software Foundation.
13 *
14 *  RoarAudio is distributed in the hope that it will be useful,
15 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *  GNU General Public License for more details.
18 *
19 *  You should have received a copy of the GNU General Public License
20 *  along with this software; see the file COPYING.  If not, write to
21 *  the Free Software Foundation, 51 Franklin Street, Fifth Floor,
22 *  Boston, MA 02110-1301, USA.
23 *
24 */
25
[5740]26#include <roard/include/roard.h>
27
[4699]28#ifndef ROAR_WITHOUT_DCOMP_EMUL_GOPHER
29#include <roaraudio/proto_gopher.h>
30
[4703]31#define _INFO  ROAR_GOPHER_TYPE_INFO
32#define _DIR   ROAR_GOPHER_TYPE_DIR
33#define _FILE  ROAR_GOPHER_TYPE_FILE
34#define _SOUND ROAR_GOPHER_TYPE_SOUND
35
[4714]36struct item;
[4712]37
[5741]38static int scb_status_txt (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara);
39static int scb_test       (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara);
40static int scb_clients    (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara);
41static int scb_streams    (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara);
42static int scb_client_info(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara);
43static int scb_stream_info(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara);
44static int scb_listen_menu(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara);
45static int scb_listen     (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara);
[4706]46
[4703]47static struct roar_gopher_menu_item g_gopher_root_menu[] = {
48 {.type = _INFO, .name = "roard Root Menu"},
[4706]49 {.type = _FILE, .name = "Server Info",   .selector = "/info.txt",   .host = NULL, .port = 0},
[4707]50 {.type = _FILE, .name = "Server Status", .selector = "/status.txt", .host = NULL, .port = 0},
51 {.type = _DIR,  .name = "Clients",       .selector = "/clients/",   .host = NULL, .port = 0},
52 {.type = _DIR,  .name = "Streams",       .selector = "/streams/",   .host = NULL, .port = 0},
[4744]53 {.type = _DIR,  .name = "Listen!",       .selector = "/listen/",    .host = NULL, .port = 0},
[4703]54};
55
[4742]56// need a true constant string.
57#define info_text \
58 "This server is RoarAudio server (roard) with a small status gopher server\n" \
59 "integrated. (For version and stuff see /status.txt.)\n" \
60 "RoarAudio is a modern, multi OS, networed sound system.\n" \
61 "For more information see http://roaraudio.keep-cool.org/\n"
62
[4703]63static struct item {
64 const char * selector;
65 char type;
66 struct roar_gopher_menu menu;
67 struct roar_audio_info  info;
68 int dir;
69 const char * text;
[5741]70 int (*cb)(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara);
[4703]71} g_gopher_items[] = {
72 {.selector = "", .type = _DIR,
[4706]73  .menu = {.items = g_gopher_root_menu, .items_len = sizeof(g_gopher_root_menu)/sizeof(*g_gopher_root_menu)},
74  .cb = NULL
[4703]75 },
76 // and again as selector '/' as some clients seems to require it:
77 {.selector = "/", .type = _DIR,
[4706]78  .menu = {.items = g_gopher_root_menu, .items_len = sizeof(g_gopher_root_menu)/sizeof(*g_gopher_root_menu)},
79  .cb = NULL
[4703]80 },
[4742]81 {.selector = "/info.txt",   .type = _FILE, .text = info_text, .cb = NULL},
[4707]82 {.selector = "/status.txt", .type = _FILE, .cb = scb_status_txt},
[4714]83 {.selector = "/test/*",     .type = _FILE, .cb = scb_test},
[4707]84 {.selector = "/clients/",   .type = _DIR,  .cb = scb_clients},
[4715]85 {.selector = "/streams/",   .type = _DIR,  .cb = scb_streams},
[4716]86 {.selector = "/clients/*/", .type = _DIR,  .cb = scb_client_info},
[4744]87 {.selector = "/streams/*/", .type = _DIR,  .cb = scb_stream_info},
88 {.selector = "/listen/",    .type = _DIR,  .cb = scb_listen_menu},
89 {.selector = "/listen/*/*/*/*/*", .type = _FILE,  .cb = scb_listen}
[4703]90};
91
[4715]92static char * _aprintf(size_t sizehint, const char * format, ...);
93
[5741]94static int send_menu (int client, struct roar_gopher_menu * menu, struct roar_vio_calls * vio, struct roar_buffer ** obuffer);
[5740]95static int send_text (const char * text, struct roar_buffer ** obuffer);
[4707]96
[4703]97
[4706]98// SCBs:
[5741]99static int scb_status_txt (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara) {
[4706]100 const size_t len = 1024;
[5740]101
[5741]102 (void)client, (void)vio, (void)selector, (void)text, (void)sitem, (void)obuffer;
[4706]103
[4714]104 *text = roar_mm_malloc(len);
[4706]105 if ( *text == NULL )
106  return -1;
107
108 **text = 0;
109
110 snprintf(*text, len,
[5741]111          "Host application:   %s\r\n"
112          "Host ABI:           %s\r\n"
[4706]113          "Server location:    %s\r\n"
114          "Server description: %s\r\n"
115          "\r\n"
[4742]116          "Counters current:   %llu clients, %llu streams\r\n"
117          "Counters sum:       %llu clients, %llu streams\r\n",
[5741]118          pluginpara->appname    == NULL ? "***unknown***" : pluginpara->appname,
119          pluginpara->abiversion == NULL ? "***unknown***" : pluginpara->abiversion,
[4706]120          g_config->location,
121          g_config->description,
122          (long long unsigned int)g_counters.cur.clients,
[4742]123          (long long unsigned int)g_counters.cur.streams,
124          (long long unsigned int)g_counters.sum.clients,
125          (long long unsigned int)g_counters.sum.streams
[4706]126         );
127
128 (*text)[len-1] = 0;
129 return 0;
130}
131
[5741]132static int scb_test(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara) {
[4714]133 ssize_t toks;
134 char * tok;
135 size_t len;
136
[5741]137 (void)client, (void)vio, (void)obuffer, (void)pluginpara;
[5740]138
[5602]139 toks = roar_mm_strseltok(sitem->selector, selector, &tok, 1);
[4714]140
141 if ( toks == -1 )
142  return -1;
143
144 len  = strlen(tok);
145 len += 64;
146
[5741]147 *text = roar_mm_malloc(len);
[4714]148 if ( *text == NULL )
149  return -1;
150
151 **text = 0;
152
153 snprintf(*text, len, "Your text was: %s", tok);
154
155 (*text)[len-1] = 0;
156
157 return 0;
158}
159
[5741]160static int scb_clients    (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara) {
[4707]161 struct roar_gopher_menu_item items[ROAR_CLIENTS_MAX];
162 struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
163 struct roar_gopher_menu_item * item;
164 struct roar_client_server * cs;
165 struct roar_client        * c;
166 const size_t len = 80;
167 char * d;
168 size_t i;
169 int ret;
170
[5741]171 (void)selector, (void)text, (void)sitem, (void)pluginpara;
[5740]172
[4707]173 memset(items, 0, sizeof(items));
174
175 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
176  if ( (c = ROAR_CLIENT((cs = g_clients[i]))) != NULL ) {
177   item = &(items[menu.items_len++]);
178   item->type = _DIR;
179   d = roar_mm_malloc(len);
180   if ( d == NULL ) {
181    menu.items_len--;
182    continue;
183   }
184   if ( c->name != NULL && c->name[0] != 0 ) {
185    snprintf(d, len, "Client %i: %s", (int)i, c->name);
186   } else {
187    snprintf(d, len, "Client %i", (int)i);
188   }
189   item->name = d;
190
191   d = roar_mm_malloc(len);
192   if ( d == NULL ) {
193    if ( item->name != NULL )
194     roar_mm_free((void*)item->name);
195    menu.items_len--;
196    continue;
197   }
198
199   snprintf(d, len, "/clients/%i/", (int)i);
200   item->selector = d;
201  }
202 }
203
[5741]204 ret = send_menu(client, &menu, vio, obuffer);
[4707]205
206 for (i = 0; i < menu.items_len; i++) {
207  if ( items[i].name != NULL )
208   roar_mm_free((void*)items[i].name);
209  if ( items[i].selector != NULL )
210   roar_mm_free((void*)items[i].selector);
211 }
212
213 return ret;
214}
215
[5741]216static int scb_streams    (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara) {
[4707]217 struct roar_gopher_menu_item items[ROAR_STREAMS_MAX];
218 struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
219 struct roar_gopher_menu_item * item;
220 struct roar_stream_server * ss;
221 struct roar_stream        * s;
222 const size_t len = 80;
223 char * d;
224 size_t i;
225 int ret;
226
[5741]227 (void)selector, (void)text, (void)sitem, (void)pluginpara;
[5740]228
[4707]229 memset(items, 0, sizeof(items));
230
231 for (i = 0; i < ROAR_STREAMS_MAX; i++) {
232  if ( (s = ROAR_STREAM((ss = g_streams[i]))) != NULL ) {
233   item = &(items[menu.items_len++]);
234   item->type = _DIR;
235   d = roar_mm_malloc(len);
236   if ( d == NULL ) {
237    menu.items_len--;
238    continue;
239   }
240   if ( ss->name != NULL && ss->name[0] != 0 ) {
241    snprintf(d, len, "Stream %i: %s", (int)i, ss->name);
242   } else {
243    snprintf(d, len, "Stream %i", (int)i);
244   }
245   item->name = d;
246
247   d = roar_mm_malloc(len);
248   if ( d == NULL ) {
249    if ( item->name != NULL )
250     roar_mm_free((void*)item->name);
251    menu.items_len--;
252    continue;
253   }
254
255   snprintf(d, len, "/streams/%i/", (int)i);
256   item->selector = d;
257  }
258 }
259
[5741]260 ret = send_menu(client, &menu, vio, obuffer);
[4707]261
262 for (i = 0; i < menu.items_len; i++) {
263  if ( items[i].name != NULL )
264   roar_mm_free((void*)items[i].name);
265  if ( items[i].selector != NULL )
266   roar_mm_free((void*)items[i].selector);
267 }
268
269 return ret;
270}
[4706]271
[5741]272static int scb_client_info(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara) {
[4716]273#define _MAX_ITEMS (16 + ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT)
[4715]274 struct roar_gopher_menu_item items[_MAX_ITEMS];
275 struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
276 struct roar_gopher_menu_item * item;
277 struct roar_client_server * cs;
278 struct roar_client        * c;
279 size_t i;
280 int ret;
281 ssize_t toks;
282 char * tok;
283 int id;
284 char tmp[80];
285
[5741]286 (void)text, (void)pluginpara;
[5740]287
[4715]288 memset(items, 0, sizeof(items));
289
[5602]290 toks = roar_mm_strseltok(sitem->selector, selector, &tok, 1);
[4715]291 if ( toks == -1 )
292  return -1;
293
294 id = atoi(tok);
295
296 if ( clients_get_server(id, &cs) == -1 )
297  return -1;
298
299 c = ROAR_CLIENT(cs);
300
301 item = &(items[menu.items_len++]);
302 item->type = _INFO;
303 if ( c->name != NULL && c->name[0] != 0 ) {
304  item->name = _aprintf(64, "Client %i: %s", id, c->name);
305 } else {
306  item->name = _aprintf(64, "Client %i", id);
307 }
308
309 if ( roar_nnode_get_socktype(&(c->nnode)) != ROAR_SOCKET_TYPE_UNKNOWN ) {
310  if ( roar_nnode_to_str(&(c->nnode), tmp, sizeof(tmp)) == 0 ) {
311   item = &(items[menu.items_len++]);
312   item->type = _INFO;
313   item->name = _aprintf(64, "Network node: %s", tmp);
314  }
315 }
316
317 item = &(items[menu.items_len++]);
318 item->type = _INFO;
319 item->name = _aprintf(64, "Protocol: %s", roar_proto2str(c->proto));
320
321 if ( c->execed != -1 ) {
322  item = &(items[menu.items_len++]);
323  item->type = _DIR;
324  item->name = _aprintf(64, "Exected Stream: %i", c->execed);
325  item->selector = _aprintf(64, "/streams/%i/", c->execed);
326 }
327
328 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
329  if ( c->streams[i] != -1 ) {
330   item = &(items[menu.items_len++]);
331   item->type = _DIR;
332   item->name = _aprintf(64, "Stream: %i", c->streams[i]);
333   item->selector = _aprintf(64, "/streams/%i/", c->streams[i]);
334  }
335 }
336
[5741]337 ret = send_menu(client, &menu, vio, obuffer);
[4715]338
339 for (i = 0; i < menu.items_len; i++) {
340  if ( items[i].name != NULL )
341   roar_mm_free((void*)items[i].name);
342  if ( items[i].selector != NULL )
343   roar_mm_free((void*)items[i].selector);
344 }
345
346#undef _MAX_ITEMS
347 return ret;
348}
349
[5741]350static int scb_stream_info(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara) {
[4716]351#define _MAX_ITEMS 12
352 struct roar_gopher_menu_item items[_MAX_ITEMS];
353 struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
354 struct roar_gopher_menu_item * item;
355 struct roar_stream_server * ss;
356 struct roar_stream        * s;
357 size_t i;
358 int ret;
359 ssize_t toks;
360 char * tok;
361 int id;
362
[5741]363 (void)text, (void)pluginpara;
[5740]364
[4716]365 memset(items, 0, sizeof(items));
366
[5602]367 toks = roar_mm_strseltok(sitem->selector, selector, &tok, 1);
[4716]368 if ( toks == -1 )
369  return -1;
370
371 id = atoi(tok);
372
373 if ( streams_get(id, &ss) == -1 )
374  return -1;
375
376 s = ROAR_STREAM(ss);
377
378
379 item = &(items[menu.items_len++]);
380 item->type = _INFO;
381 if ( ss->name != NULL && ss->name[0] != 0 ) {
382  item->name = _aprintf(64, "Stream %i: %s", id, ss->name);
383 } else {
384  item->name = _aprintf(64, "Stream %i", id);
385 }
386
387 item = &(items[menu.items_len++]);
388 item->type = _INFO;
389 item->name = _aprintf(64, "Stream state: %s", roar_streamstate2str(ss->state));
390
391 item = &(items[menu.items_len++]);
392 item->type = _INFO;
393 item->name = _aprintf(64, "Stream direction: %s", roar_dir2str(s->dir));
394
395 item = &(items[menu.items_len++]);
396 item->type = _INFO;
397 item->name = _aprintf(128, "Signal info: rate:%iHz bits:%i channels:%i codec:%s",
398                            s->info.rate, s->info.bits, s->info.channels, roar_codec2str(s->info.codec));
399
[5740]400 if ( ss->codec_orgi != ROAR_AUDIO_INFO_INVALID && ss->codec_orgi != s->info.codec ) {
[4716]401  item = &(items[menu.items_len++]);
402  item->type = _INFO;
403  item->name = _aprintf(64, "Streamed codec: %s", roar_codec2str(ss->codec_orgi));
404 }
405
406 if ( ss->role != -1 ) {
407  item = &(items[menu.items_len++]);
408  item->type = _INFO;
409  item->name = _aprintf(64, "Stream role: %s", roar_role2str(ss->role));
410 }
411
412 item = &(items[menu.items_len++]);
413 item->type = _DIR;
414 item->name = _aprintf(64, "Client: %i", ss->client);
415 item->selector = _aprintf(64, "/clients/%i/", ss->client);
416
[5741]417 ret = send_menu(client, &menu, vio, obuffer);
[4716]418
419 for (i = 0; i < menu.items_len; i++) {
420  if ( items[i].name != NULL )
421   roar_mm_free((void*)items[i].name);
422  if ( items[i].selector != NULL )
423   roar_mm_free((void*)items[i].selector);
424 }
425
426#undef _MAX_ITEMS
427 return ret;
428}
429
[5741]430static int scb_listen_menu(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara) {
[4744]431#define _MAX_ITEMS 12
432 struct roar_gopher_menu_item items[_MAX_ITEMS];
433 struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
434 struct roar_gopher_menu_item * item;
435 const char * codec;
436 int ret;
437 int codecs[] = {ROAR_CODEC_DEFAULT, ROAR_CODEC_RIFF_WAVE, ROAR_CODEC_AU, ROAR_CODEC_OGG_VORBIS};
438 size_t i;
439
[5741]440 (void)selector, (void)text, (void)sitem, (void)pluginpara;
[5740]441
[4744]442 memset(items, 0, sizeof(items));
443
444 item = &(items[menu.items_len++]);
445 item->type = _INFO;
446 item->name = roar_mm_strdup("Select a format you want to listen in:");
447
448 item = &(items[menu.items_len++]);
449 item->type = _INFO;
450 item->name = NULL; // empty lion
451
452 for (i = 0; i < (sizeof(codecs)/sizeof(*codecs)); i++) {
453  item = &(items[menu.items_len++]);
454  item->type = _SOUND;
455  codec = roar_codec2str(codecs[i]);
456  item->name = _aprintf(64, "%u channels with %u bits at %uHz, %s",
457                            g_sa->channels, g_sa->bits, g_sa->rate, codec);
458  item->selector = _aprintf(64, "/listen/monitor/%u/%u/%u/%s", g_sa->rate, g_sa->bits, g_sa->channels, codec);
459 }
460
[5741]461 ret = send_menu(client, &menu, vio, obuffer);
[4744]462
463 for (i = 0; i < menu.items_len; i++) {
464  if ( items[i].name != NULL )
465   roar_mm_free((void*)items[i].name);
466  if ( items[i].selector != NULL )
467   roar_mm_free((void*)items[i].selector);
468 }
469
470#undef _MAX_ITEMS
471 return ret;
472}
473
[5741]474static int scb_listen     (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem, struct roar_buffer ** obuffer, struct roar_dl_librarypara * pluginpara) {
[4744]475 struct roar_stream_server * ss;
476 struct roar_stream        * s;
477 struct roar_audio_info info;
478 int dir = -1;
479 ssize_t toks;
480 char * tok[5];
481 int stream = -1;
482
[5741]483 (void)vio, (void)text, (void)obuffer, (void)pluginpara;
[5740]484
[5602]485 toks = roar_mm_strseltok(sitem->selector, selector, tok, 5);
[4744]486
487 if ( toks != 5 )
488  return -1;
489
490 memset(&info, 0, sizeof(info));
491
492 if ( (dir = roar_str2dir(tok[0])) == -1 )
493  return -1;
494
495 // test for unsupported dirs:
496 switch (dir) {
497  case ROAR_DIR_THRU:
498  case ROAR_DIR_RAW_IN:
499  case ROAR_DIR_FILTER:
500    return -1;
501   break;
502 }
503
504 info.rate     = atoi(tok[1]);
505 info.bits     = atoi(tok[2]);
506 info.channels = atoi(tok[3]);
507 info.codec    = roar_str2codec(tok[4]);
508
[5740]509 if ( info.codec == ROAR_AUDIO_INFO_INVALID )
[4744]510  return -1;
511
512 if ((stream = streams_new()) == -1 )
513  return -1;
514
515 if ( streams_get(stream, &ss) == -1 ) {
516  streams_delete(stream);
517  return -1;
518 }
519
520 s = ROAR_STREAM(ss);
521
522 if ( client_stream_add(client, stream) == -1 ) {
523  streams_delete(stream);
524  return -1;
525 }
526
527 memcpy(&(s->info), &info, sizeof(info));
528 ss->codec_orgi = info.codec;
529
530 if ( streams_set_dir(stream, dir, 1) == -1 ) {
531  streams_delete(stream);
532  return -1;
533 }
534
535 if ( client_stream_exec(client, stream) == -1 ) {
536  streams_delete(stream);
537  return -1;
538 }
539
540 return 0;
541}
542
[4706]543// other code:
[4703]544static int strip_nl (char * str) {
545 register char c;
546
547 for (; (c = *str) != 0; str++) {
548  if ( c == '\r' || c == '\n' ) {
549   *str = 0;
550   return 1;
551  }
552 }
553
554 return 0;
555}
556
[4715]557static char * _aprintf(size_t sizehint, const char * format, ...) {
558 va_list ap;
559 char * buf;
560 int ret;
561
562 sizehint += 128;
563
564 if ( (buf = roar_mm_malloc(sizehint)) == NULL )
565  return NULL;
566
567 va_start(ap, format);
568 ret = vsnprintf(buf, sizehint, format, ap);
569 va_end(ap);
570
571 buf[sizehint-1] = 0;
572
573 return buf;
574}
575
[5741]576static int send_menu (int client, struct roar_gopher_menu * menu, struct roar_vio_calls * vio, struct roar_buffer ** obuffer) {
[4703]577 struct roar_buffer * buf;
578 struct roar_gopher_menu_item * item;
[4744]579 const size_t len = 256;
[4703]580 size_t i;
581 void * data;
582 char * chardata;
[4705]583 const char * host;
[4704]584 unsigned int port;
[4705]585 struct roar_sockname sockaddr;
586
[5741]587 (void)client;
588
[4705]589 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_GET_SOCKNAME, &sockaddr) == -1 ) {
590  memset(&sockaddr, 0, sizeof(sockaddr));
591 }
[4703]592
593 for (i = 0; i < menu->items_len; i++) {
594  item = &(menu->items[i]);
[4705]595  if ( roar_buffer_new_data(&buf, len, &data) == -1 ) {
596   if ( sockaddr.addr != NULL )
597    roar_mm_free(sockaddr.addr);
[4703]598   return -1;
[4705]599  }
[4703]600
601  chardata = data;
602
603  switch (item->type) {
604   case _INFO:
[4744]605     snprintf(data, len-1, "i%s\tfake\t(NULL)\t0\r\n", item->name == NULL ? "" : item->name);
[4703]606    break;
607   default:
[5740]608     host = item->host == NULL ?               sockaddr.addr : item->host;
609     port = item->port ==    0 ? (unsigned int)sockaddr.port : item->port;
[4704]610     snprintf(data, len-1, "%c%s\t%s\t%s\t%u\r\n", item->type, item->name, item->selector, host, port);
[4703]611    break;
612  }
613
614  chardata[len-1] = 0;
615
[5242]616  if ( roar_buffer_set_len(buf, strlen(data)) == -1 ) {
617   roar_buffer_free(buf);
[5741]618   if ( sockaddr.addr != NULL )
619    roar_mm_free(sockaddr.addr);
[5242]620   return -1;
621  }
[4703]622
[5741]623  if ( roar_buffer_moveintoqueue(obuffer, &buf) == -1 ) {
624   roar_buffer_free(buf);
625   if ( sockaddr.addr != NULL )
626    roar_mm_free(sockaddr.addr);
627   return -1;
628  }
[4703]629 }
630
[4705]631 if ( sockaddr.addr != NULL )
632  roar_mm_free(sockaddr.addr);
633
[4703]634 return 0;
635}
636
[5740]637static int send_text (const char * text, struct roar_buffer ** obuffer) {
[4703]638 struct roar_buffer * buf;
639 void * data;
640 size_t len = strlen(text);
641
642 if ( roar_buffer_new_data(&buf, len+6, &data) == -1 )
643  return -1;
644
645 memcpy(data, text, len);
[4706]646 //memcpy(data+len, "\r\n.\r\n\0", 6);
647 memcpy(data+len, "\0", 1);
[5740]648 if ( roar_buffer_moveintoqueue(obuffer, &buf) == -1 )
649  return -1;
[4703]650
651 return 0;
652}
653
[5739]654static int emul_gopher_check_client(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) {
[4703]655 struct roar_client_server * cs;
656 struct item * c = NULL;
657 char inbuf[1024];
658 ssize_t ret;
659 size_t i;
660 int funcret = -1;
661 size_t len = 0;
662 void * data;
[4706]663 char * text;
[4703]664
[5740]665 (void)obuffer, (void)userdata, (void)protopara, (void)protoparalen, (void)pluginpara;
666
[4714]667 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
668
[4703]669 if ( clients_get_server(client, &cs) == -1 ) {
670  return -1;
671 }
672
[4714]673 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
674
675 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
676
[4703]677 if ( cs->inbuf != NULL ) {
678  len = sizeof(inbuf)-1;
679  if ( roar_buffer_shift_out(&(cs->inbuf), inbuf, &len) == -1 ) {
680   return -1;
681  }
682
683  if ( cs->inbuf != NULL ) {
684   roar_buffer_free(cs->inbuf);
685   return -1;
686  }
687
688  // test if we have still buffer space left.
689  if ( len == (sizeof(inbuf)-1) ) {
690   return -1;
691  }
692 }
693
[4714]694 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
695
[4703]696 ret = roar_vio_read(vio, inbuf+len, sizeof(inbuf)-len-1);
697 if ( ret < 1 ) {
[4714]698  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
[4703]699  return -1;
700 }
701
702 ret += len;
703
704 inbuf[ret] = 0;
705
[4714]706 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
707
[4703]708 if ( !strip_nl(inbuf) ) {
709  if ( roar_buffer_new_data(&(cs->inbuf), ret, &data) == -1 ) {
[4714]710   ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
[4703]711   return -1;
712  }
713
714  memcpy(data, inbuf, ret);
[4714]715
716  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = 0", client, vio);
717
[4703]718  return 0;
719 }
720
[4714]721 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
722
[4703]723 for (i = 0; i < sizeof(g_gopher_items)/sizeof(*g_gopher_items); i++) {
[5602]724//  if ( !roar_mm_strselcmp(g_gopher_items[i].selector, inbuf) ) {
725  if ( !roar_mm_strselcmp(g_gopher_items[i].selector, inbuf) ) {
[4703]726   c = &(g_gopher_items[i]);
727   break;
728  }
729 }
730
731 if ( c == NULL ) {
[4714]732  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
[4703]733  return -1;
734 }
735
[4714]736 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
737
[4706]738 if ( c->cb != NULL ) {
739  text = NULL;
[5741]740  funcret = c->cb(client, vio, inbuf, &text, c, obuffer, pluginpara);
[4706]741
742  if ( funcret == 0 && text != NULL )
[5740]743   funcret = send_text(text, obuffer);
[4706]744
745  if ( text != NULL )
746   roar_mm_free(text);
747 } else {
748  switch (c->type) {
749   case _DIR:
[5741]750     funcret = send_menu(client, &(c->menu), vio, obuffer);
[4706]751    break;
752   case _FILE:
[5740]753     funcret = send_text(c->text, obuffer);
[4706]754    break;
755   default:
756     funcret = -1;
757    break;
758  }
[4703]759 }
760
[4714]761 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
762
[4703]763 if ( funcret == -1 ) {
[4714]764  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
[4703]765  return -1;
766 }
767
[4714]768 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = 0", client, vio);
769
[4703]770 return 0;
771}
772
[5739]773static int emul_gopher_flushed_client(int client, struct roar_vio_calls * vio, struct roar_buffer ** obuffer, void ** userdata, const struct roar_keyval * protopara, ssize_t protoparalen, struct roar_dl_librarypara * pluginpara) {
[5740]774
775 (void)client, (void)vio, (void)obuffer, (void)userdata, (void)protopara, (void)protoparalen, (void)pluginpara;
776
[4714]777 ROAR_DBG("emul_gopher_flushed_client(client=%i, vio=%p) = ?", client, vio);
778
[5739]779 return -1;
[4703]780}
781
[5740]782static struct roar_dl_proto __proto_common_gopher = {
[5739]783 .proto = ROAR_PROTO_GOPHER,
784 .description = "The Internet Gopher Protocol",
785 .flags = ROAR_DL_PROTO_FLAGS_NONE,
786 .handle = emul_gopher_check_client,
787 .flushed = emul_gopher_flushed_client
788};
789
[5740]790static int __reg_proto(struct roar_dl_librarypara * para, struct roar_dl_libraryinst * lib) {
791 (void)para, (void)lib;
792 ROAR_DL_PLUGIN_REG_FN(ROAR_DL_PROTO_SUBTYPE, __proto_common_gopher, ROAR_DL_PROTO_VERSION);
793 return 0;
794}
795
796ROAR_DL_PLUGIN_START(protocol_gopher) {
797 ROARD_DL_CHECK_VERSIONS();
798
799 ROAR_DL_PLUGIN_META_PRODUCT_NIV("protocol-gopher", ROAR_VID_ROARAUDIO, ROAR_VNAME_ROARAUDIO);
800 ROAR_DL_PLUGIN_META_VERSION(ROAR_VERSION_STRING);
801 ROAR_DL_PLUGIN_META_LICENSE_TAG(GPLv3_0);
802 ROAR_DL_PLUGIN_META_CONTACT_FLNE("Philipp", "Schafft", "ph3-der-loewe", "lion@lion.leolix.org");
803 ROAR_DL_PLUGIN_META_DESC("Implementation of the Internet Gopher protocol");
804
805 ROAR_DL_PLUGIN_REG(ROAR_DL_FN_PROTO, __reg_proto);
806} ROAR_DL_PLUGIN_END
807
[4699]808#endif
809
810//ll
Note: See TracBrowser for help on using the repository browser.