Rename "subsystems" directory to "base"
[oonf.git] / src / base / oonf_viewer.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon version 2 (olsrd2)
4  * Copyright (c) 2004-2015, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 /**
43  * @file
44  */
45
46 #include <oonf/base/oonf_viewer.h>
47 #include <oonf/libcommon/autobuf.h>
48 #include <oonf/oonf.h>
49 #include <oonf/libcommon/json.h>
50 #include <oonf/libcommon/template.h>
51 #include <oonf/libcore/oonf_subsystem.h>
52 #include <oonf/base/oonf_telnet.h> /* compile-time dependency */
53
54 /* Definitions */
55 #define LOG_VIEWER _oonf_viewer_subsystem.logging
56
57 /* static function prototypes */
58 static int _init(void);
59 static void _cleanup(void);
60
61 /* Template call help text for telnet */
62 static const char _telnet_help[] = "\n"
63                                    "Use '" OONF_VIEWER_JSON_FORMAT "' as the first parameter"
64                                    " ' to generate JSON output of all keys/value pairs.\n"
65                                    "Use '" OONF_VIEWER_JSON_RAW_FORMAT "' as the first parameter"
66                                    " to generate JSON output of all keys/value pairs"
67                                    "  without isoprefixes for numbers.\n"
68                                    "Use '" OONF_VIEWER_HEAD_FORMAT "' as the first parameter to"
69                                    " generate a headline for the table.\n"
70                                    "Use '" OONF_VIEWER_RAW_FORMAT "' as the first parameter to"
71                                    " generate a headline for the table without isoprefixes for numbers.\n"
72                                    "You can also add a custom template (text with keys inside)"
73                                    " as the last parameter instead.\n";
74
75 /* subsystem definition */
76 static struct oonf_subsystem _oonf_viewer_subsystem = {
77   .name = OONF_VIEWER_SUBSYSTEM,
78   .init = _init,
79   .cleanup = _cleanup,
80 };
81 DECLARE_OONF_PLUGIN(_oonf_viewer_subsystem);
82
83 /**
84  * Initialize telnet subsystem
85  * @return always returns 0
86  */
87 static int
88 _init(void) {
89   return 0;
90 }
91
92 /**
93  * Cleanup all allocated data of telnet subsystem
94  */
95 static void
96 _cleanup(void) {}
97
98 /**
99  * Prepare a viewer template for output. The create_json and
100  * create_raw variable should be initialized before calling this
101  * function.
102  * @param template pointer to viewer template
103  * @param storage pointer to autobuffer template storage that should
104  *     be printed
105  * @param out pointer to output buffer
106  * @param format pointer to template for output, not used for JSON output
107  */
108 void
109 oonf_viewer_output_prepare(struct oonf_viewer_template *template, struct abuf_template_storage *storage,
110   struct autobuf *out, const char *format) {
111   template->out = out;
112
113   if (template->create_json) {
114     /* JSON format */
115     template->_storage = NULL;
116     json_init_session(&template->_json, out);
117
118     /* start wrapper object */
119     if (!template->create_only_data) {
120       json_start_object(&template->_json, NULL);
121     }
122
123     /* start object with array */
124     json_start_array(&template->_json, template->json_name);
125   }
126   else {
127     if (format && *format == 0) {
128       format = NULL;
129     }
130
131     /* no JSON format, generate template entries */
132     template->_storage = storage;
133     abuf_template_init_ext(template->_storage, template->data, template->data_size, format);
134   }
135 }
136
137 /**
138  * Print a link of output as a text table or JSON object. The data
139  * for the output is collected from the value buffers of the template
140  * storage array stored in the template.
141  * @param template pointer to viewer template
142  */
143 void
144 oonf_viewer_output_print_line(struct oonf_viewer_template *template) {
145   if (!template->create_json) {
146     abuf_add_template(template->out, template->_storage, false);
147     abuf_puts(template->out, "\n");
148   }
149   else {
150     /* JSON output */
151     json_start_object(&template->_json, NULL);
152     json_print_templates(&template->_json, template->data, template->data_size);
153     json_end_object(&template->_json);
154   }
155 }
156
157 /**
158  * Finalize the output of a text table or JSON object
159  * @param template pointer to viewer template
160  */
161 void
162 oonf_viewer_output_finish(struct oonf_viewer_template *template) {
163   if (template->create_json) {
164     json_end_array(&template->_json);
165     if (!template->create_only_data) {
166       json_end_object(&template->_json);
167     }
168   }
169 }
170
171 /**
172  * Print telnet help text for array of templates
173  * @param out output buffer
174  * @param parameter parameter of help command
175  * @param template pointer to template array
176  * @param count number of elements in template array
177  */
178 void
179 oonf_viewer_print_help(
180   struct autobuf *out, const char *parameter, struct oonf_viewer_template *template, size_t count) {
181   size_t i, j, k;
182
183   if (parameter == NULL || *parameter == 0) {
184     abuf_puts(out, "Available subcommands:\n");
185
186     for (i = 0; i < count; i++) {
187       if (template[i].help_line) {
188         abuf_appendf(out, "\t%s: %s\n", template[i].json_name, template[i].help_line);
189       }
190       else {
191         abuf_appendf(out, "\t%s\n", template[i].json_name);
192       }
193     }
194
195     abuf_puts(out, _telnet_help);
196     abuf_puts(out, "Use 'help <command> <subcommand>' to get help about a subcommand\n");
197     return;
198   }
199   for (i = 0; i < count; i++) {
200     if (strcmp(parameter, template[i].json_name) == 0) {
201       if (template[i].help) {
202         abuf_puts(out, template[i].help);
203       }
204       abuf_appendf(out, "The subcommand '%s' has the following keys:\n", template[i].json_name);
205
206       for (j = 0; j < template[i].data_size; j++) {
207         for (k = 0; k < template[i].data[j].count; k++) {
208           abuf_appendf(out, "\t%%%s%%\n", template[i].data[j].data[k].key);
209         }
210       }
211
212       abuf_puts(out, _telnet_help);
213       return;
214     }
215   }
216
217   abuf_appendf(out, "Unknown subcommand %s\n", parameter);
218 }
219
220 /**
221  * Parse the parameter of a telnet call to run the callback of the
222  * corresponding template command. This function both prepares and
223  * finishes a viewer template.
224  * @param out pointer to output buffer
225  * @param storage pointer to autobuffer template storage
226  * @param param parameter of telnet call
227  * @param templates pointer to array of viewer templates
228  * @param count number of elements in viewer template array
229  * @return -1 if an error happened, 0 otherwise
230  */
231 int
232 oonf_viewer_call_subcommands(struct autobuf *out, struct abuf_template_storage *storage, const char *param,
233   struct oonf_viewer_template *templates, size_t count) {
234   const char *next = NULL, *ptr = NULL;
235   int result = 0;
236   size_t i;
237   bool head = false;
238   bool json = false;
239   bool raw = false;
240   bool data = false;
241
242   if ((next = str_hasnextword(param, OONF_VIEWER_HEAD_FORMAT))) {
243     head = true;
244   }
245   else if ((next = str_hasnextword(param, OONF_VIEWER_JSON_FORMAT))) {
246     json = true;
247   }
248   else if ((next = str_hasnextword(param, OONF_VIEWER_RAW_FORMAT))) {
249     raw = true;
250   }
251   else if ((next = str_hasnextword(param, OONF_VIEWER_JSON_RAW_FORMAT))) {
252     json = true;
253     raw = true;
254   }
255   else if ((next = str_hasnextword(param, OONF_VIEWER_DATA_FORMAT))) {
256     json = true;
257     data = true;
258   }
259   else if ((next = str_hasnextword(param, OONF_VIEWER_DATA_RAW_FORMAT))) {
260     json = true;
261     raw = true;
262     data = true;
263   }
264   else {
265     next = param;
266   }
267
268   for (i = 0; i < count; i++) {
269     if ((ptr = str_hasnextword(next, templates[i].json_name))) {
270       templates[i].create_json = json;
271       templates[i].create_raw = raw;
272       templates[i].create_only_data = data;
273
274       oonf_viewer_output_prepare(&templates[i], storage, out, ptr);
275
276       if (head) {
277         abuf_add_template(out, templates[i]._storage, true);
278         abuf_puts(out, "\n");
279       }
280       else {
281         result = templates[i].cb_function(&templates[i]);
282       }
283
284       oonf_viewer_output_finish(&templates[i]);
285
286       return result;
287     }
288   }
289   return 1;
290 }
291
292 /**
293  * Handles a telnet command for a viewer including error handling
294  * @param out output buffer
295  * @param storage template storage object
296  * @param cmd telnet command
297  * @param param telnet parameter(s)
298  * @param templates template viewer array
299  * @param count number of template viewer entries
300  * @return telnet return code
301  */
302 enum oonf_telnet_result
303 oonf_viewer_telnet_handler(struct autobuf *out, struct abuf_template_storage *storage, const char *cmd,
304   const char *param, struct oonf_viewer_template *templates, size_t count)
305 {
306   int result;
307
308   /* sanity check */
309   if (param == NULL || *param == 0) {
310     abuf_appendf(out, "Error, '%s' command needs a parameter\n", cmd);
311   }
312
313   /* call template based subcommands */
314   result = oonf_viewer_call_subcommands(out, storage, param, templates, count);
315   if (result == 0) {
316     return TELNET_RESULT_ACTIVE;
317   }
318   if (result < 0) {
319     return TELNET_RESULT_INTERNAL_ERROR;
320   }
321
322   abuf_appendf(out, "Unknown parameter for command '%s': %s\n", cmd, param);
323   return TELNET_RESULT_ACTIVE;
324 }
325
326 /**
327  * Handles a telnet help command for a viewer including error handling
328  * @param out output buffer
329  * @param cmd telnet command
330  * @param parameter telnet parameter(s)
331  * @param template viewer template array
332  * @param count number of template viewer entries
333  * @return telnet return coce
334  */
335 enum oonf_telnet_result
336 oonf_viewer_telnet_help(
337   struct autobuf *out, const char *cmd, const char *parameter, struct oonf_viewer_template *template, size_t count)
338 {
339   const char *next;
340
341   /* skip the layer2info command, NULL output is acceptable */
342   next = str_hasnextword(parameter, cmd);
343
344   /* print out own help text */
345   abuf_appendf(out, "%s command:\n", cmd);
346   oonf_viewer_print_help(out, next, template, count);
347
348   return TELNET_RESULT_ACTIVE;
349 }