source: roaraudio/plugins/roard/protocol-gopher.c @ 4742:14aa2c42403d

Last change on this file since 4742:14aa2c42403d was 4742:14aa2c42403d, checked in by phi, 13 years ago

some more infos

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