source: roaraudio/plugins/roard/protocol-gopher.c @ 5740:b3aff85876f1

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

commit 1: Moved protocol support into new plugins protocol-esound, protocol-rplay and protocol-gopher (Closes: #311)

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