source: roaraudio/plugins/roard/protocol-gopher.c @ 5301:f3e9cd30574d

Last change on this file since 5301:f3e9cd30574d was 5301:f3e9cd30574d, checked in by phi, 12 years ago

move away from roar_buffer_add() (See: #126)

File size: 22.3 KB
Line 
1//emul_gopher.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010-2011
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.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);
39static int scb_test       (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem);
40static int scb_clients    (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem);
41static int scb_streams    (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem);
42static int scb_client_info(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem);
43static int scb_stream_info(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem);
44static int scb_listen_menu(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem);
45static int scb_listen     (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem);
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);
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 int strselcmp(const char *s1, const char *s2);
93static ssize_t strseltok(const char *s1, char *s2, char ** tok, size_t toks);
94
95static char * _aprintf(size_t sizehint, const char * format, ...);
96
97static int send_menu (int client, struct roar_gopher_menu * menu, struct roar_vio_calls * vio);
98static int send_text (int client, const char * text, struct roar_vio_calls * vio);
99
100
101// SCBs:
102static int scb_status_txt (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem) {
103 const size_t len = 1024;
104 const char * server_version = NULL;
105
106 if ( DISTRIBUTION_VERSION_STRING[0] == 0 ) {
107  server_version = "roard/" PACKAGE_VERSION " <" DEVICE_VENDOR_STRING ">";
108 } else {
109  server_version = "roard/" PACKAGE_VERSION " <" DEVICE_VENDOR_STRING "> (" DISTRIBUTION_VERSION_STRING ")";
110 }
111
112 *text = roar_mm_malloc(len);
113 if ( *text == NULL )
114  return -1;
115
116 **text = 0;
117
118 snprintf(*text, len,
119          "Server version:     %s\r\n"
120          "Server location:    %s\r\n"
121          "Server description: %s\r\n"
122          "\r\n"
123          "Counters current:   %llu clients, %llu streams\r\n"
124          "Counters sum:       %llu clients, %llu streams\r\n",
125          server_version,
126          g_config->location,
127          g_config->description,
128          (long long unsigned int)g_counters.cur.clients,
129          (long long unsigned int)g_counters.cur.streams,
130          (long long unsigned int)g_counters.sum.clients,
131          (long long unsigned int)g_counters.sum.streams
132         );
133
134 (*text)[len-1] = 0;
135 return 0;
136}
137
138static int scb_test(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem) {
139 ssize_t toks;
140 char * tok;
141 size_t len;
142
143 toks = strseltok(sitem->selector, selector, &tok, 1);
144
145 if ( toks == -1 )
146  return -1;
147
148 len  = strlen(tok);
149 len += 64;
150
151 *text = roar_mm_malloc(1024);
152 if ( *text == NULL )
153  return -1;
154
155 **text = 0;
156
157 snprintf(*text, len, "Your text was: %s", tok);
158
159 (*text)[len-1] = 0;
160
161 return 0;
162}
163
164static int scb_clients    (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem) {
165 struct roar_gopher_menu_item items[ROAR_CLIENTS_MAX];
166 struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
167 struct roar_gopher_menu_item * item;
168 struct roar_client_server * cs;
169 struct roar_client        * c;
170 const size_t len = 80;
171 char * d;
172 size_t i;
173 int ret;
174
175 memset(items, 0, sizeof(items));
176
177 for (i = 0; i < ROAR_CLIENTS_MAX; i++) {
178  if ( (c = ROAR_CLIENT((cs = g_clients[i]))) != NULL ) {
179   item = &(items[menu.items_len++]);
180   item->type = _DIR;
181   d = roar_mm_malloc(len);
182   if ( d == NULL ) {
183    menu.items_len--;
184    continue;
185   }
186   if ( c->name != NULL && c->name[0] != 0 ) {
187    snprintf(d, len, "Client %i: %s", (int)i, c->name);
188   } else {
189    snprintf(d, len, "Client %i", (int)i);
190   }
191   item->name = d;
192
193   d = roar_mm_malloc(len);
194   if ( d == NULL ) {
195    if ( item->name != NULL )
196     roar_mm_free((void*)item->name);
197    menu.items_len--;
198    continue;
199   }
200
201   snprintf(d, len, "/clients/%i/", (int)i);
202   item->selector = d;
203  }
204 }
205
206 ret = send_menu(client, &menu, vio);
207
208 for (i = 0; i < menu.items_len; i++) {
209  if ( items[i].name != NULL )
210   roar_mm_free((void*)items[i].name);
211  if ( items[i].selector != NULL )
212   roar_mm_free((void*)items[i].selector);
213 }
214
215 return ret;
216}
217
218static int scb_streams    (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem) {
219 struct roar_gopher_menu_item items[ROAR_STREAMS_MAX];
220 struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
221 struct roar_gopher_menu_item * item;
222 struct roar_stream_server * ss;
223 struct roar_stream        * s;
224 const size_t len = 80;
225 char * d;
226 size_t i;
227 int ret;
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);
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) {
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 memset(items, 0, sizeof(items));
287
288 toks = strseltok(sitem->selector, selector, &tok, 1);
289 if ( toks == -1 )
290  return -1;
291
292 id = atoi(tok);
293
294 if ( clients_get_server(id, &cs) == -1 )
295  return -1;
296
297 c = ROAR_CLIENT(cs);
298
299 item = &(items[menu.items_len++]);
300 item->type = _INFO;
301 if ( c->name != NULL && c->name[0] != 0 ) {
302  item->name = _aprintf(64, "Client %i: %s", id, c->name);
303 } else {
304  item->name = _aprintf(64, "Client %i", id);
305 }
306
307 if ( roar_nnode_get_socktype(&(c->nnode)) != ROAR_SOCKET_TYPE_UNKNOWN ) {
308  if ( roar_nnode_to_str(&(c->nnode), tmp, sizeof(tmp)) == 0 ) {
309   item = &(items[menu.items_len++]);
310   item->type = _INFO;
311   item->name = _aprintf(64, "Network node: %s", tmp);
312  }
313 }
314
315 item = &(items[menu.items_len++]);
316 item->type = _INFO;
317 item->name = _aprintf(64, "Protocol: %s", roar_proto2str(c->proto));
318
319 if ( c->execed != -1 ) {
320  item = &(items[menu.items_len++]);
321  item->type = _DIR;
322  item->name = _aprintf(64, "Exected Stream: %i", c->execed);
323  item->selector = _aprintf(64, "/streams/%i/", c->execed);
324 }
325
326 for (i = 0; i < ROAR_CLIENTS_MAX_STREAMS_PER_CLIENT; i++) {
327  if ( c->streams[i] != -1 ) {
328   item = &(items[menu.items_len++]);
329   item->type = _DIR;
330   item->name = _aprintf(64, "Stream: %i", c->streams[i]);
331   item->selector = _aprintf(64, "/streams/%i/", c->streams[i]);
332  }
333 }
334
335 ret = send_menu(client, &menu, vio);
336
337 for (i = 0; i < menu.items_len; i++) {
338  if ( items[i].name != NULL )
339   roar_mm_free((void*)items[i].name);
340  if ( items[i].selector != NULL )
341   roar_mm_free((void*)items[i].selector);
342 }
343
344#undef _MAX_ITEMS
345 return ret;
346}
347
348static int scb_stream_info(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem) {
349#define _MAX_ITEMS 12
350 struct roar_gopher_menu_item items[_MAX_ITEMS];
351 struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
352 struct roar_gopher_menu_item * item;
353 struct roar_stream_server * ss;
354 struct roar_stream        * s;
355 size_t i;
356 int ret;
357 ssize_t toks;
358 char * tok;
359 int id;
360
361 memset(items, 0, sizeof(items));
362
363 toks = strseltok(sitem->selector, selector, &tok, 1);
364 if ( toks == -1 )
365  return -1;
366
367 id = atoi(tok);
368
369 if ( streams_get(id, &ss) == -1 )
370  return -1;
371
372 s = ROAR_STREAM(ss);
373
374
375 item = &(items[menu.items_len++]);
376 item->type = _INFO;
377 if ( ss->name != NULL && ss->name[0] != 0 ) {
378  item->name = _aprintf(64, "Stream %i: %s", id, ss->name);
379 } else {
380  item->name = _aprintf(64, "Stream %i", id);
381 }
382
383 item = &(items[menu.items_len++]);
384 item->type = _INFO;
385 item->name = _aprintf(64, "Stream state: %s", roar_streamstate2str(ss->state));
386
387 item = &(items[menu.items_len++]);
388 item->type = _INFO;
389 item->name = _aprintf(64, "Stream direction: %s", roar_dir2str(s->dir));
390
391 item = &(items[menu.items_len++]);
392 item->type = _INFO;
393 item->name = _aprintf(128, "Signal info: rate:%iHz bits:%i channels:%i codec:%s",
394                            s->info.rate, s->info.bits, s->info.channels, roar_codec2str(s->info.codec));
395
396 if ( ss->codec_orgi != -1 && ss->codec_orgi != s->info.codec ) {
397  item = &(items[menu.items_len++]);
398  item->type = _INFO;
399  item->name = _aprintf(64, "Streamed codec: %s", roar_codec2str(ss->codec_orgi));
400 }
401
402 if ( ss->role != -1 ) {
403  item = &(items[menu.items_len++]);
404  item->type = _INFO;
405  item->name = _aprintf(64, "Stream role: %s", roar_role2str(ss->role));
406 }
407
408 item = &(items[menu.items_len++]);
409 item->type = _DIR;
410 item->name = _aprintf(64, "Client: %i", ss->client);
411 item->selector = _aprintf(64, "/clients/%i/", ss->client);
412
413 ret = send_menu(client, &menu, vio);
414
415 for (i = 0; i < menu.items_len; i++) {
416  if ( items[i].name != NULL )
417   roar_mm_free((void*)items[i].name);
418  if ( items[i].selector != NULL )
419   roar_mm_free((void*)items[i].selector);
420 }
421
422#undef _MAX_ITEMS
423 return ret;
424}
425
426static int scb_listen_menu(int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem) {
427#define _MAX_ITEMS 12
428 struct roar_gopher_menu_item items[_MAX_ITEMS];
429 struct roar_gopher_menu menu = {.flags = 0, .items = items, .items_len = 0};
430 struct roar_gopher_menu_item * item;
431 const char * codec;
432 int ret;
433 int codecs[] = {ROAR_CODEC_DEFAULT, ROAR_CODEC_RIFF_WAVE, ROAR_CODEC_AU, ROAR_CODEC_OGG_VORBIS};
434 size_t i;
435
436 memset(items, 0, sizeof(items));
437
438 item = &(items[menu.items_len++]);
439 item->type = _INFO;
440 item->name = roar_mm_strdup("Select a format you want to listen in:");
441
442 item = &(items[menu.items_len++]);
443 item->type = _INFO;
444 item->name = NULL; // empty lion
445
446 for (i = 0; i < (sizeof(codecs)/sizeof(*codecs)); i++) {
447  item = &(items[menu.items_len++]);
448  item->type = _SOUND;
449  codec = roar_codec2str(codecs[i]);
450  item->name = _aprintf(64, "%u channels with %u bits at %uHz, %s",
451                            g_sa->channels, g_sa->bits, g_sa->rate, codec);
452  item->selector = _aprintf(64, "/listen/monitor/%u/%u/%u/%s", g_sa->rate, g_sa->bits, g_sa->channels, codec);
453 }
454
455 ret = send_menu(client, &menu, vio);
456
457 for (i = 0; i < menu.items_len; i++) {
458  if ( items[i].name != NULL )
459   roar_mm_free((void*)items[i].name);
460  if ( items[i].selector != NULL )
461   roar_mm_free((void*)items[i].selector);
462 }
463
464#undef _MAX_ITEMS
465 return ret;
466}
467
468static int scb_listen     (int client, struct roar_vio_calls * vio, char * selector, char ** text, struct item * sitem) {
469 struct roar_stream_server * ss;
470 struct roar_stream        * s;
471 struct roar_audio_info info;
472 int dir = -1;
473 ssize_t toks;
474 char * tok[5];
475 int stream = -1;
476
477 toks = strseltok(sitem->selector, selector, tok, 5);
478
479 if ( toks != 5 )
480  return -1;
481
482 memset(&info, 0, sizeof(info));
483
484 if ( (dir = roar_str2dir(tok[0])) == -1 )
485  return -1;
486
487 // test for unsupported dirs:
488 switch (dir) {
489  case ROAR_DIR_THRU:
490  case ROAR_DIR_RAW_IN:
491  case ROAR_DIR_FILTER:
492    return -1;
493   break;
494 }
495
496 info.rate     = atoi(tok[1]);
497 info.bits     = atoi(tok[2]);
498 info.channels = atoi(tok[3]);
499 info.codec    = roar_str2codec(tok[4]);
500
501 if ( info.codec == -1 )
502  return -1;
503
504 if ((stream = streams_new()) == -1 )
505  return -1;
506
507 if ( streams_get(stream, &ss) == -1 ) {
508  streams_delete(stream);
509  return -1;
510 }
511
512 s = ROAR_STREAM(ss);
513
514 if ( client_stream_add(client, stream) == -1 ) {
515  streams_delete(stream);
516  return -1;
517 }
518
519 memcpy(&(s->info), &info, sizeof(info));
520 ss->codec_orgi = info.codec;
521
522 if ( streams_set_dir(stream, dir, 1) == -1 ) {
523  streams_delete(stream);
524  return -1;
525 }
526
527 if ( client_stream_exec(client, stream) == -1 ) {
528  streams_delete(stream);
529  return -1;
530 }
531
532 return 0;
533}
534
535// other code:
536static int strip_nl (char * str) {
537 register char c;
538
539 for (; (c = *str) != 0; str++) {
540  if ( c == '\r' || c == '\n' ) {
541   *str = 0;
542   return 1;
543  }
544 }
545
546 return 0;
547}
548
549static int strselcmp(const char *s1, const char *s2) {
550 register char a, b;
551
552 if ( s1 == s2 )
553  return 0;
554
555 if ( s1 == NULL || s2 == NULL )
556  return -1;
557
558 for (; ; s1++, s2++) {
559  a = *s1;
560  b = *s2;
561
562  if ( a == '*' ) {
563   s1++;
564   a = *s1;
565   if ( a == 0 ) {
566    if ( b == 0 ) {
567     return 1; // no match! ('*' does not mach no-chars)
568    } else {
569     return 0; // match! (string ends with '*' and something not EOS is in b)
570    }
571   } else {
572    for (; *s2 != 0 && *s2 != a; s2++);
573    if ( a != *s2 )
574     return 1; // no match! (did not find correct char)
575   }
576  } else if ( a == 0 || b == 0 ) {
577   if ( a == b ) {
578    return 0; // match!
579   } else {
580    return 1; // no match! (dffrent length)
581   }
582  } else if ( a != b ) {
583   return 1; // no match! (diffrent chars)
584  }
585 }
586
587 return -1;
588}
589
590static ssize_t strseltok(const char *s1, char *s2, char ** tok, size_t toks) {
591 register char a, b;
592 size_t idx = 0;
593
594 if ( s1 == NULL || s2 == NULL )
595  return -1;
596
597 for (; ; s1++, s2++) {
598  a = *s1;
599  b = *s2;
600
601  if ( a == 0 || b == 0 ) {
602   if ( a == b ) {
603    return idx;
604   } else {
605    return -1;
606   }
607  } else if ( a == '*' ) {
608   s1++;
609   a = *s1;
610   if ( idx == toks )
611    return -1;
612
613   tok[idx] = s2;
614   idx++;
615
616   for (; *s2 != 0 && *s2 != a; s2++);
617
618   if ( a == 0 )
619    return idx;
620
621   if ( *s1 == 0 )
622    return -1;
623
624   *s2 = 0;
625  }
626 }
627
628 return -1;
629}
630
631static char * _aprintf(size_t sizehint, const char * format, ...) {
632 va_list ap;
633 char * buf;
634 int ret;
635
636 sizehint += 128;
637
638 if ( (buf = roar_mm_malloc(sizehint)) == NULL )
639  return NULL;
640
641 va_start(ap, format);
642 ret = vsnprintf(buf, sizehint, format, ap);
643 va_end(ap);
644
645 buf[sizehint-1] = 0;
646
647 return buf;
648}
649
650static int send_menu (int client, struct roar_gopher_menu * menu, struct roar_vio_calls * vio) {
651 struct roar_buffer * buf;
652 struct roar_gopher_menu_item * item;
653 const size_t len = 256;
654 size_t i;
655 void * data;
656 char * chardata;
657 const char * host;
658 unsigned int port;
659 struct roar_sockname sockaddr;
660
661 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_GET_SOCKNAME, &sockaddr) == -1 ) {
662  memset(&sockaddr, 0, sizeof(sockaddr));
663 }
664
665 for (i = 0; i < menu->items_len; i++) {
666  item = &(menu->items[i]);
667  if ( roar_buffer_new_data(&buf, len, &data) == -1 ) {
668   if ( sockaddr.addr != NULL )
669    roar_mm_free(sockaddr.addr);
670   return -1;
671  }
672
673  chardata = data;
674
675  switch (item->type) {
676   case _INFO:
677     snprintf(data, len-1, "i%s\tfake\t(NULL)\t0\r\n", item->name == NULL ? "" : item->name);
678    break;
679   default:
680     host = item->host == NULL ? sockaddr.addr : item->host;
681     port = item->port ==    0 ? sockaddr.port : item->port;
682     snprintf(data, len-1, "%c%s\t%s\t%s\t%u\r\n", item->type, item->name, item->selector, host, port);
683    break;
684  }
685
686  chardata[len-1] = 0;
687
688  if ( roar_buffer_set_len(buf, strlen(data)) == -1 ) {
689   roar_buffer_free(buf);
690   return -1;
691  }
692
693  clients_add_output(client, &buf);
694 }
695
696 if ( sockaddr.addr != NULL )
697  roar_mm_free(sockaddr.addr);
698
699 return 0;
700}
701
702static int send_text (int client, const char * text, struct roar_vio_calls * vio) {
703 struct roar_buffer * buf;
704 void * data;
705 size_t len = strlen(text);
706
707 if ( roar_buffer_new_data(&buf, len+6, &data) == -1 )
708  return -1;
709
710 memcpy(data, text, len);
711 //memcpy(data+len, "\r\n.\r\n\0", 6);
712 memcpy(data+len, "\0", 1);
713 clients_add_output(client, &buf);
714
715 return 0;
716}
717
718int emul_gopher_check_client(int client, struct roar_vio_calls * vio) {
719 struct roar_client_server * cs;
720 struct roar_vio_calls     rvio;
721 struct item * c = NULL;
722 char inbuf[1024];
723 ssize_t ret;
724 size_t i;
725 int funcret = -1;
726 size_t len = 0;
727 void * data;
728 char * text;
729
730 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
731
732 if ( clients_get_server(client, &cs) == -1 ) {
733  clients_delete(client);
734  return -1;
735 }
736
737 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
738
739 if ( vio == NULL ) {
740  vio = &rvio;
741  roar_vio_open_fh_socket(vio, clients_get_fh(client));
742 }
743
744 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
745
746 if ( cs->inbuf != NULL ) {
747  len = sizeof(inbuf)-1;
748  if ( roar_buffer_shift_out(&(cs->inbuf), inbuf, &len) == -1 ) {
749   clients_delete(client);
750   return -1;
751  }
752
753  if ( cs->inbuf != NULL ) {
754   roar_buffer_free(cs->inbuf);
755   clients_delete(client);
756   return -1;
757  }
758
759  // test if we have still buffer space left.
760  if ( len == (sizeof(inbuf)-1) ) {
761   clients_delete(client);
762   return -1;
763  }
764 }
765
766 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
767
768 ret = roar_vio_read(vio, inbuf+len, sizeof(inbuf)-len-1);
769 if ( ret < 1 ) {
770  clients_delete(client);
771  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
772  return -1;
773 }
774
775 ret += len;
776
777 inbuf[ret] = 0;
778
779 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
780
781 if ( !strip_nl(inbuf) ) {
782  if ( roar_buffer_new_data(&(cs->inbuf), ret, &data) == -1 ) {
783   clients_delete(client);
784   ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
785   return -1;
786  }
787
788  memcpy(data, inbuf, ret);
789
790  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = 0", client, vio);
791
792  return 0;
793 }
794
795 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
796
797 for (i = 0; i < sizeof(g_gopher_items)/sizeof(*g_gopher_items); i++) {
798//  if ( !strselcmp(g_gopher_items[i].selector, inbuf) ) {
799  if ( !strselcmp(g_gopher_items[i].selector, inbuf) ) {
800   c = &(g_gopher_items[i]);
801   break;
802  }
803 }
804
805 if ( c == NULL ) {
806  clients_delete(client);
807  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
808  return -1;
809 }
810
811 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
812
813 if ( c->cb != NULL ) {
814  text = NULL;
815  funcret = c->cb(client, vio, inbuf, &text, c);
816
817  if ( funcret == 0 && text != NULL )
818   funcret = send_text(client, text, vio);
819
820  if ( text != NULL )
821   roar_mm_free(text);
822 } else {
823  switch (c->type) {
824   case _DIR:
825     funcret = send_menu(client, &(c->menu), vio);
826    break;
827   case _FILE:
828     funcret = send_text(client, c->text, vio);
829    break;
830   default:
831     funcret = -1;
832    break;
833  }
834 }
835
836 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = ?", client, vio);
837
838 if ( funcret == -1 ) {
839  clients_delete(client);
840  ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = -1", client, vio);
841  return -1;
842 }
843
844 ROAR_DBG("emul_gopher_check_client(client=%i, vio=%p) = 0", client, vio);
845
846 return 0;
847}
848
849int emul_gopher_flushed_client(int client, struct roar_vio_calls * vio) {
850 ROAR_DBG("emul_gopher_flushed_client(client=%i, vio=%p) = ?", client, vio);
851
852 return clients_delete(client);
853}
854
855#endif
856
857//ll
Note: See TracBrowser for help on using the repository browser.