source: roaraudio/plugins/roard/protocol-gopher.c @ 4706:b24a7aa8f563

Last change on this file since 4706:b24a7aa8f563 was 4706:b24a7aa8f563, checked in by phi, 13 years ago

added cb based selector generation and added a small status page

File size: 7.0 KB
Line 
1//emul_gopher.c:
2
3/*
4 *      Copyright (C) Philipp 'ph3-der-loewe' Schafft - 2010
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
36static int scb_status_txt (int client, struct roar_vio_calls * vio, const char * selector, char ** text);
37
38static struct roar_gopher_menu_item g_gopher_root_menu[] = {
39 {.type = _INFO, .name = "roard Root Menu"},
40 {.type = _FILE, .name = "Server Info",   .selector = "/info.txt",   .host = NULL, .port = 0},
41 {.type = _FILE, .name = "Server Status", .selector = "/status.txt", .host = NULL, .port = 0}
42};
43
44static struct item {
45 const char * selector;
46 char type;
47 struct roar_gopher_menu menu;
48 struct roar_audio_info  info;
49 int dir;
50 const char * text;
51 int (*cb)(int client, struct roar_vio_calls * vio, const char * selector, char ** text);
52} g_gopher_items[] = {
53 {.selector = "", .type = _DIR,
54  .menu = {.items = g_gopher_root_menu, .items_len = sizeof(g_gopher_root_menu)/sizeof(*g_gopher_root_menu)},
55  .cb = NULL
56 },
57 // and again as selector '/' as some clients seems to require it:
58 {.selector = "/", .type = _DIR,
59  .menu = {.items = g_gopher_root_menu, .items_len = sizeof(g_gopher_root_menu)/sizeof(*g_gopher_root_menu)},
60  .cb = NULL
61 },
62 {.selector = "/info.txt",   .type = _FILE, .text = "Some\nText.", .cb = NULL},
63 {.selector = "/status.txt", .type = _FILE, .cb = scb_status_txt}
64};
65
66
67// SCBs:
68static int scb_status_txt (int client, struct roar_vio_calls * vio, const char * selector, char ** text) {
69 const size_t len = 1024;
70 const char * server_version = NULL;
71
72 if ( DISTRIBUTION_VERSION_STRING[0] == 0 ) {
73  server_version = "roard/" PACKAGE_VERSION " <" DEVICE_VENDOR_STRING ">";
74 } else {
75  server_version = "roard/" PACKAGE_VERSION " <" DEVICE_VENDOR_STRING "> (" DISTRIBUTION_VERSION_STRING ")";
76 }
77
78 *text = roar_mm_malloc(1024);
79 if ( *text == NULL )
80  return -1;
81
82 **text = 0;
83
84 snprintf(*text, len,
85          "Server version:     %s\r\n"
86          "Server location:    %s\r\n"
87          "Server description: %s\r\n"
88          "\r\n"
89          "Counters current:   %llu clients, %llu streams\r\n",
90          server_version,
91          g_config->location,
92          g_config->description,
93          (long long unsigned int)g_counters.cur.clients,
94          (long long unsigned int)g_counters.cur.streams
95         );
96
97 (*text)[len-1] = 0;
98 return 0;
99}
100
101
102// other code:
103static int strip_nl (char * str) {
104 register char c;
105
106 for (; (c = *str) != 0; str++) {
107  if ( c == '\r' || c == '\n' ) {
108   *str = 0;
109   return 1;
110  }
111 }
112
113 return 0;
114}
115
116static int send_menu (int client, struct roar_gopher_menu * menu, struct roar_vio_calls * vio) {
117 struct roar_buffer * buf;
118 struct roar_gopher_menu_item * item;
119 const size_t len = 80;
120 size_t i;
121 void * data;
122 char * chardata;
123 const char * host;
124 unsigned int port;
125 struct roar_sockname sockaddr;
126
127 if ( roar_vio_ctl(vio, ROAR_VIO_CTL_GET_SOCKNAME, &sockaddr) == -1 ) {
128  memset(&sockaddr, 0, sizeof(sockaddr));
129 }
130
131 for (i = 0; i < menu->items_len; i++) {
132  item = &(menu->items[i]);
133  if ( roar_buffer_new_data(&buf, len, &data) == -1 ) {
134   if ( sockaddr.addr != NULL )
135    roar_mm_free(sockaddr.addr);
136   return -1;
137  }
138
139  chardata = data;
140
141  switch (item->type) {
142   case _INFO:
143     snprintf(data, len-1, "i%s\tfake\t(NULL)\t0\r\n", item->name);
144    break;
145   default:
146     host = item->host == NULL ? sockaddr.addr : item->host;
147     port = item->port ==    0 ? sockaddr.port : item->port;
148     snprintf(data, len-1, "%c%s\t%s\t%s\t%u\r\n", item->type, item->name, item->selector, host, port);
149    break;
150  }
151
152  chardata[len-1] = 0;
153
154  roar_buffer_set_len(buf, strlen(data));
155
156  clients_add_output(client, buf);
157 }
158
159 if ( sockaddr.addr != NULL )
160  roar_mm_free(sockaddr.addr);
161
162 return 0;
163}
164
165static int send_text (int client, const char * text, struct roar_vio_calls * vio) {
166 struct roar_buffer * buf;
167 void * data;
168 size_t len = strlen(text);
169
170 if ( roar_buffer_new_data(&buf, len+6, &data) == -1 )
171  return -1;
172
173 memcpy(data, text, len);
174 //memcpy(data+len, "\r\n.\r\n\0", 6);
175 memcpy(data+len, "\0", 1);
176 clients_add_output(client, buf);
177
178 return 0;
179}
180
181int emul_gopher_check_client(int client, struct roar_vio_calls * vio) {
182 struct roar_client_server * cs;
183 struct roar_vio_calls     rvio;
184 struct item * c = NULL;
185 char inbuf[1024];
186 ssize_t ret;
187 size_t i;
188 int funcret = -1;
189 size_t len = 0;
190 void * data;
191 char * text;
192
193 if ( clients_get_server(client, &cs) == -1 ) {
194  clients_delete(client);
195  return -1;
196 }
197
198 if ( vio == NULL ) {
199  vio = &rvio;
200  roar_vio_open_fh_socket(vio, clients_get_fh(client));
201 }
202
203 if ( cs->inbuf != NULL ) {
204  len = sizeof(inbuf)-1;
205  if ( roar_buffer_shift_out(&(cs->inbuf), inbuf, &len) == -1 ) {
206   clients_delete(client);
207   return -1;
208  }
209
210  if ( cs->inbuf != NULL ) {
211   roar_buffer_free(cs->inbuf);
212   clients_delete(client);
213   return -1;
214  }
215
216  // test if we have still buffer space left.
217  if ( len == (sizeof(inbuf)-1) ) {
218   clients_delete(client);
219   return -1;
220  }
221 }
222
223 ret = roar_vio_read(vio, inbuf+len, sizeof(inbuf)-len-1);
224 if ( ret < 1 ) {
225  clients_delete(client);
226  return -1;
227 }
228
229 ret += len;
230
231 inbuf[ret] = 0;
232
233 if ( !strip_nl(inbuf) ) {
234  if ( roar_buffer_new_data(&(cs->inbuf), ret, &data) == -1 ) {
235   clients_delete(client);
236   return -1;
237  }
238
239  memcpy(data, inbuf, ret);
240  return 0;
241 }
242
243 for (i = 0; i < sizeof(g_gopher_items)/sizeof(*g_gopher_items); i++) {
244  if ( !strcmp(g_gopher_items[i].selector, inbuf) ) {
245   c = &(g_gopher_items[i]);
246   break;
247  }
248 }
249
250 if ( c == NULL ) {
251  clients_delete(client);
252  return -1;
253 }
254
255 if ( c->cb != NULL ) {
256  text = NULL;
257  funcret = c->cb(client, vio, inbuf, &text);
258
259  if ( funcret == 0 && text != NULL )
260   funcret = send_text(client, text, vio);
261
262  if ( text != NULL )
263   roar_mm_free(text);
264 } else {
265  switch (c->type) {
266   case _DIR:
267     funcret = send_menu(client, &(c->menu), vio);
268    break;
269   case _FILE:
270     funcret = send_text(client, c->text, vio);
271    break;
272   default:
273     funcret = -1;
274    break;
275  }
276 }
277
278 if ( funcret == -1 ) {
279  clients_delete(client);
280  return -1;
281 }
282
283 return 0;
284}
285
286int emul_gopher_flushed_client(int client, struct roar_vio_calls * vio) {
287 return clients_delete(client);
288}
289
290#endif
291
292//ll
Note: See TracBrowser for help on using the repository browser.