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
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 ROAR_WITHOUT_DCOMP_EMUL_GOPHER
29#include <roaraudio/proto_gopher.h>
30
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
36struct item;
37
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);
46
47static struct roar_gopher_menu_item g_gopher_root_menu[] = {
48 {.type = _INFO, .name = "roard Root Menu"},
49 {.type = _FILE, .name = "Server Info",   .selector = "/info.txt",   .host = NULL, .port = 0},
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},
53 {.type = _DIR,  .name = "Listen!",       .selector = "/listen/",    .host = NULL, .port = 0},
54};
55
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
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;
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);
71} g_gopher_items[] = {
72 {.selector = "", .type = _DIR,
73  .menu = {.items = g_gopher_root_menu, .items_len = sizeof(g_gopher_root_menu)/sizeof(*g_gopher_root_menu)},
74  .cb = NULL
75 },
76 // and again as selector '/' as some clients seems to require it:
77 {.selector = "/", .type = _DIR,
78  .menu = {.items = g_gopher_root_menu, .items_len = sizeof(g_gopher_root_menu)/sizeof(*g_gopher_root_menu)},
79  .cb = NULL
80 },
81 {.selector = "/info.txt",   .type = _FILE, .text = info_text, .cb = NULL},
82 {.selector = "/status.txt", .type = _FILE, .cb = scb_status_txt},
83 {.selector = "/test/*",     .type = _FILE, .cb = scb_test},
84 {.selector = "/clients/",   .type = _DIR,  .cb = scb_clients},
85 {.selector = "/streams/",   .type = _DIR,  .cb = scb_streams},
86 {.selector = "/clients/*/", .type = _DIR,  .cb = scb_client_info},
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}
90};
91
92static char * _aprintf(size_t sizehint, const char * format, ...);
93
94static int send_menu (int client, struct roar_gopher_menu * menu, struct roar_vio_calls * vio, struct roar_buffer ** obuffer);
95static int send_text (const char * text, struct roar_buffer ** obuffer);
96
97
98// SCBs:
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) {
100 const size_t len = 1024;
101
102 (void)client, (void)vio, (void)selector, (void)text, (void)sitem, (void)obuffer;
103
104 *text = roar_mm_malloc(len);
105 if ( *text == NULL )
106  return -1;
107
108 **text = 0;
109
110 snprintf(*text, len,
111          "Host application:   %s\r\n"
112          "Host ABI:           %s\r\n"
113          "Server location:    %s\r\n"
114          "Server description: %s\r\n"
115          "\r\n"
116          "Counters current:   %llu clients, %llu streams\r\n"
117          "Counters sum:       %llu clients, %llu streams\r\n",
118          pluginpara->appname    == NULL ? "***unknown***" : pluginpara->appname,
119          pluginpara->abiversion == NULL ? "***unknown***" : pluginpara->abiversion,
120          g_config->location,
121          g_config->description,
122          (long long unsigned int)g_counters.cur.clients,
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
126         );
127
128 (*text)[len-1] = 0;
129 return 0;
130}
131
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) {
133 ssize_t toks;
134 char * tok;
135 size_t len;
136
137 (void)client, (void)vio, (void)obuffer, (void)pluginpara;
138
139 toks = roar_mm_strseltok(sitem->selector, selector, &tok, 1);
140
141 if ( toks == -1 )
142  return -1;
143
144 len  = strlen(tok);
145 len += 64;
146
147 *text = roar_mm_malloc(len);
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
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) {
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
171 (void)selector, (void)text, (void)sitem, (void)pluginpara;
172
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
204 ret = send_menu(client, &menu, vio, obuffer);
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
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) {
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
227 (void)selector, (void)text, (void)sitem, (void)pluginpara;
228
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
260 ret = send_menu(client, &menu, vio, obuffer);
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}
271
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) {
273#define _MAX_ITEMS (16 + ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT)
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
286 (void)text, (void)pluginpara;
287
288 memset(items, 0, sizeof(items));
289
290 toks = roar_mm_strseltok(sitem->selector, selector, &tok, 1);
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
337 ret = send_menu(client, &menu, vio, obuffer);
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
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) {
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
363 (void)text, (void)pluginpara;
364
365 memset(items, 0, sizeof(items));
366
367 toks = roar_mm_strseltok(sitem->selector, selector, &tok, 1);
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
400 if ( ss->codec_orgi != ROAR_AUDIO_INFO_INVALID && ss->codec_orgi != s->info.codec ) {
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
417 ret = send_menu(client, &menu, vio, obuffer);
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
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) {
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
440 (void)selector, (void)text, (void)sitem, (void)pluginpara;
441
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
461 ret = send_menu(client, &menu, vio, obuffer);
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
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) {
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
483 (void)vio, (void)text, (void)obuffer, (void)pluginpara;
484
485 toks = roar_mm_strseltok(sitem->selector, selector, tok, 5);
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
509 if ( info.codec == ROAR_AUDIO_INFO_INVALID )
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
543// other code:
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
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
576static int send_menu (int client, struct roar_gopher_menu * menu, struct roar_vio_calls * vio, struct roar_buffer ** obuffer) {
577 struct roar_buffer * buf;
578 struct roar_gopher_menu_item * item;
579 const size_t len = 256;
580 size_t i;
581 void * data;
582 char * chardata;
583 const char * host;
584 unsigned int port;
585 struct roar_sockname sockaddr;
586
587 (void)client;
588
589 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_GET_SOCKNAME, &sockaddr) == -1 ) {
590  memset(&sockaddr, 0, sizeof(sockaddr));
591 }
592
593 for (i = 0; i < menu->items_len; i++) {
594  item = &(menu->items[i]);
595  if ( roar_buffer_new_data(&buf, len, &data) == -1 ) {
596   if ( sockaddr.addr != NULL )
597    roar_mm_free(sockaddr.addr);
598   return -1;
599  }
600
601  chardata = data;
602
603  switch (item->type) {
604   case _INFO:
605     snprintf(data, len-1, "i%s\tfake\t(NULL)\t0\r\n", item->name == NULL ? "" : item->name);
606    break;
607   default:
608     host = item->host == NULL ?               sockaddr.addr : item->host;
609     port = item->port ==    0 ? (unsigned int)sockaddr.port : item->port;
610     snprintf(data, len-1, "%c%s\t%s\t%s\t%u\r\n", item->type, item->name, item->selector, host, port);
611    break;
612  }
613
614  chardata[len-1] = 0;
615
616  if ( roar_buffer_set_len(buf, strlen(data)) == -1 ) {
617   roar_buffer_free(buf);
618   if ( sockaddr.addr != NULL )
619    roar_mm_free(sockaddr.addr);
620   return -1;
621  }
622
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  }
629 }
630
631 if ( sockaddr.addr != NULL )
632  roar_mm_free(sockaddr.addr);
633
634 return 0;
635}
636
637static int send_text (const char * text, struct roar_buffer ** obuffer) {
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);
646 //memcpy(data+len, "\r\n.\r\n\0", 6);
647 memcpy(data+len, "\0", 1);
648 if ( roar_buffer_moveintoqueue(obuffer, &buf) == -1 )
649  return -1;
650
651 return 0;
652}
653
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) {
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;
663 char * text;
664
665 (void)obuffer, (void)userdata, (void)protopara, (void)protoparalen, (void)pluginpara;
666
667 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
668
669 if ( clients_get_server(client, &cs) == -1 ) {
670  return -1;
671 }
672
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
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
694 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
695
696 ret = roar_vio_read(vio, inbuf+len, sizeof(inbuf)-len-1);
697 if ( ret < 1 ) {
698  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
699  return -1;
700 }
701
702 ret += len;
703
704 inbuf[ret] = 0;
705
706 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
707
708 if ( !strip_nl(inbuf) ) {
709  if ( roar_buffer_new_data(&(cs->inbuf), ret, &data) == -1 ) {
710   ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
711   return -1;
712  }
713
714  memcpy(data, inbuf, ret);
715
716  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = 0", client, vio);
717
718  return 0;
719 }
720
721 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
722
723 for (i = 0; i < sizeof(g_gopher_items)/sizeof(*g_gopher_items); i++) {
724//  if ( !roar_mm_strselcmp(g_gopher_items[i].selector, inbuf) ) {
725  if ( !roar_mm_strselcmp(g_gopher_items[i].selector, inbuf) ) {
726   c = &(g_gopher_items[i]);
727   break;
728  }
729 }
730
731 if ( c == NULL ) {
732  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
733  return -1;
734 }
735
736 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
737
738 if ( c->cb != NULL ) {
739  text = NULL;
740  funcret = c->cb(client, vio, inbuf, &text, c, obuffer, pluginpara);
741
742  if ( funcret == 0 && text != NULL )
743   funcret = send_text(text, obuffer);
744
745  if ( text != NULL )
746   roar_mm_free(text);
747 } else {
748  switch (c->type) {
749   case _DIR:
750     funcret = send_menu(client, &(c->menu), vio, obuffer);
751    break;
752   case _FILE:
753     funcret = send_text(c->text, obuffer);
754    break;
755   default:
756     funcret = -1;
757    break;
758  }
759 }
760
761 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
762
763 if ( funcret == -1 ) {
764  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
765  return -1;
766 }
767
768 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = 0", client, vio);
769
770 return 0;
771}
772
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) {
774
775 (void)client, (void)vio, (void)obuffer, (void)userdata, (void)protopara, (void)protoparalen, (void)pluginpara;
776
777 ROAR_DBG("emul_gopher_flushed_client(client=%i, vio=%p) = ?", client, vio);
778
779 return -1;
780}
781
782static struct roar_dl_proto __proto_common_gopher = {
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
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
808#endif
809
810//ll
Note: See TracBrowser for help on using the repository browser.