6cb465bcff6faed7cc9504b24552fcc3b4d83327
[oonf.git] / src / core / olsr_telnet.c
1 /*
2  * olsr_telnet.c
3  *
4  *  Created on: Sep 7, 2011
5  *      Author: rogge
6  */
7
8 #include "common/common_types.h"
9 #include "common/avl.h"
10 #include "common/avl_comp.h"
11
12 #include "config/cfg_schema.h"
13
14 #include "olsr_cfg.h"
15 #include "olsr_logging.h"
16 #include "olsr_memcookie.h"
17 #include "olsr_netaddr_acl.h"
18 #include "olsr_plugins.h"
19 #include "olsr_stream_socket.h"
20 #include "olsr_timer.h"
21 #include "olsr.h"
22 #include "olsr_telnet.h"
23
24 /* static function prototypes */
25 static void _call_stop_handler(struct olsr_telnet_data *data);
26 static void _cb_config_changed(void);
27 static int _cb_telnet_init(struct olsr_stream_session *);
28 static void _cb_telnet_cleanup(struct olsr_stream_session *);
29 static void _cb_telnet_create_error(struct olsr_stream_session *,
30     enum olsr_stream_errors);
31 static enum olsr_stream_session_state _cb_telnet_receive_data(
32     struct olsr_stream_session *);
33 static enum olsr_telnet_result _telnet_handle_command(
34     struct olsr_telnet_data *);
35 static struct olsr_telnet_command *_check_telnet_command(
36     struct olsr_telnet_data *data, const char *name,
37     struct olsr_telnet_command *cmd);
38
39 static void _cb_telnet_repeat_timer(void *data);
40 static enum olsr_telnet_result _cb_telnet_quit(struct olsr_telnet_data *data);
41 static enum olsr_telnet_result _cb_telnet_help(struct olsr_telnet_data *data);
42 static enum olsr_telnet_result _cb_telnet_echo(struct olsr_telnet_data *data);
43 static enum olsr_telnet_result _cb_telnet_repeat(struct olsr_telnet_data *data);
44 static enum olsr_telnet_result _cb_telnet_timeout(struct olsr_telnet_data *data);
45 static enum olsr_telnet_result _cb_telnet_version(struct olsr_telnet_data *data);
46 static enum olsr_telnet_result _cb_telnet_plugin(struct olsr_telnet_data *data);
47
48 /* global and static variables */
49 static struct cfg_schema_section telnet_section = {
50   .type = "telnet",
51   .mode = CFG_SSMODE_UNNAMED_OPTIONAL_STARTUP_TRIGGER,
52   .help = "Settings for the telnet interface",
53   .cb_delta_handler = _cb_config_changed,
54 };
55
56 static struct cfg_schema_entry telnet_entries[] = {
57   CFG_MAP_ACL_V46(olsr_stream_managed_config,
58       acl, "acl", "127.0.0.1", "Access control list for telnet interface"),
59   CFG_MAP_NETADDR_V4(olsr_stream_managed_config,
60       bindto_v4, "bindto_v4", "127.0.0.1", "Bind telnet ipv4 socket to this address", false),
61   CFG_MAP_NETADDR_V6(olsr_stream_managed_config,
62       bindto_v6, "bindto_v6", "::1", "Bind telnet ipv6 socket to this address", false),
63   CFG_MAP_INT_MINMAX(olsr_stream_managed_config,
64       port, "port", "2006", "Network port for telnet interface", 1, 65535),
65 };
66
67 /* built-in telnet commands */
68 static struct olsr_telnet_command _builtin[] = {
69   TELNET_CMD("quit", _cb_telnet_quit, "Ends telnet session"),
70   TELNET_CMD("exit", _cb_telnet_quit, "Ends telnet session"),
71   TELNET_CMD("help", _cb_telnet_help,
72       "help: Display the online help text and a list of commands"),
73   TELNET_CMD("echo", _cb_telnet_echo,"echo <string>: Prints a string"),
74   TELNET_CMD("repeat", _cb_telnet_repeat,
75       "repeat <seconds> <command>: Repeats a telnet command every X seconds"),
76   TELNET_CMD("timeout", _cb_telnet_timeout,
77       "timeout <seconds> :Sets telnet session timeout"),
78   TELNET_CMD("version", _cb_telnet_version, "Displays version of the program"),
79   TELNET_CMD("plugin", _cb_telnet_plugin,
80         "control plugins dynamically, parameters are 'list',"
81         " 'activate <plugin>', 'deactivate <plugin>', "
82         "'load <plugin>' and 'unload <plugin>'"),
83 };
84
85 /* remember if initialized or not */
86 OLSR_SUBSYSTEM_STATE(_telnet_state);
87
88 /* telnet session handling */
89 static struct olsr_stream_managed _telnet_managed;
90 static struct olsr_memcookie_info _telnet_memcookie = {
91   .name = "telnet session",
92   .size = sizeof(struct olsr_telnet_session),
93 };
94 static struct olsr_timer_info _telnet_repeat_timerinfo = {
95   .name = "txt repeat timer",
96   .callback = _cb_telnet_repeat_timer,
97   .periodic = true,
98 };
99
100 struct avl_tree telnet_cmd_tree;
101
102 /**
103  * Initialize telnet subsystem
104  */
105 void
106 olsr_telnet_init(void) {
107   size_t i;
108
109   if (olsr_subsystem_init(&_telnet_state))
110     return;
111
112   olsr_memcookie_add(&_telnet_memcookie);
113   olsr_timer_add(&_telnet_repeat_timerinfo );
114
115   cfg_schema_add_section(olsr_cfg_get_schema(), &telnet_section,
116       telnet_entries, ARRAYSIZE(telnet_entries));
117
118   olsr_stream_add_managed(&_telnet_managed);
119   _telnet_managed.config.session_timeout = 120000; /* 120 seconds */
120   _telnet_managed.config.maximum_input_buffer = 4096;
121   _telnet_managed.config.allowed_sessions = 3;
122   _telnet_managed.config.memcookie = &_telnet_memcookie;
123   _telnet_managed.config.init = _cb_telnet_init;
124   _telnet_managed.config.cleanup = _cb_telnet_cleanup;
125   _telnet_managed.config.receive_data = _cb_telnet_receive_data;
126   _telnet_managed.config.create_error = _cb_telnet_create_error;
127
128   /* initialize telnet commands */
129   avl_init(&telnet_cmd_tree, avl_comp_strcasecmp, false, NULL);
130   for (i=0; i<ARRAYSIZE(_builtin); i++) {
131     olsr_telnet_add(&_builtin[i]);
132   }
133 }
134
135 /**
136  * Cleanup all allocated data of telnet subsystem
137  */
138 void
139 olsr_telnet_cleanup(void) {
140   if (olsr_subsystem_cleanup(&_telnet_state))
141     return;
142
143   olsr_stream_remove_managed(&_telnet_managed, true);
144   cfg_schema_remove_section(olsr_cfg_get_schema(), &telnet_section);
145   olsr_memcookie_remove(&_telnet_memcookie);
146 }
147
148 /**
149  * Add a new telnet command to telnet subsystem
150  * @param command pointer to initialized telnet command object
151  * @return -1 if an error happened, 0 otherwise
152  */
153 int
154 olsr_telnet_add(struct olsr_telnet_command *command) {
155   command->node.key = command->command;
156   if (avl_insert(&telnet_cmd_tree, &command->node)) {
157     return -1;
158   }
159   return 0;
160 }
161
162 /**
163  * Remove a telnet command from telnet subsystem
164  * @param command pointer to telnet command object
165  */
166 void
167 olsr_telnet_remove(struct olsr_telnet_command *command) {
168   avl_remove(&telnet_cmd_tree, &command->node);
169 }
170
171 void
172 olsr_telnet_stop(struct olsr_telnet_data *data) {
173   _call_stop_handler(data);
174   data->show_echo = true;
175   abuf_puts(data->out, "> ");
176   olsr_telnet_flush_session(data);
177 }
178
179 /**
180  * Execute a telnet command.
181  * @param cmd pointer to name of command
182  * @param para pointer to parameter string
183  * @param out buffer for output of command
184  * @param remote pointer to address which triggers the execution
185  * @return result of telnet command
186  */
187 enum olsr_telnet_result
188 olsr_telnet_execute(const char *cmd, const char *para,
189     struct autobuf *out, struct netaddr *remote) {
190   struct olsr_telnet_data data;
191   enum olsr_telnet_result result;
192
193   memset(&data, 0, sizeof(data));
194   data.command = cmd;
195   data.parameter = para;
196   data.out = out;
197   data.remote = remote;
198
199   result = _telnet_handle_command(&data);
200   olsr_telnet_stop(&data);
201   return result;
202 }
203
204 /**
205  * Handler for configuration changes
206  */
207 static void
208 _cb_config_changed(void) {
209   struct olsr_stream_managed_config config;
210
211   /* generate binary config */
212   memset(&config, 0, sizeof(config));
213   if (cfg_schema_tobin(&config, telnet_section.post,
214       telnet_entries, ARRAYSIZE(telnet_entries))) {
215     /* error in conversion */
216     OLSR_WARN(LOG_TELNET, "Cannot map telnet config to binary data");
217     goto apply_config_failed;
218   }
219
220   if (olsr_stream_apply_managed(&_telnet_managed, &config)) {
221     /* error while updating sockets */
222     goto apply_config_failed;
223   }
224
225   /* fall through */
226 apply_config_failed:
227   olsr_acl_remove(&config.acl);
228 }
229
230 /**
231  * Initialization of incoming telnet session
232  * @param session pointer to TCP session
233  * @return 0
234  */
235 static int
236 _cb_telnet_init(struct olsr_stream_session *session) {
237   struct olsr_telnet_session *telnet_session;
238
239   /* get telnet session pointer */
240   telnet_session = (struct olsr_telnet_session *)session;
241
242   telnet_session->data.show_echo = true;
243   telnet_session->data.stop_handler = NULL;
244   telnet_session->data.timeout_value = 120000;
245   telnet_session->data.out = &telnet_session->session.out;
246   telnet_session->data.remote = &telnet_session->session.remote_address;
247
248   list_init_head(&telnet_session->data.cleanup_list);
249
250   return 0;
251 }
252
253 /**
254  * Cleanup of telnet session
255  * @param session pointer to TCP session
256  */
257 static void
258 _cb_telnet_cleanup(struct olsr_stream_session *session) {
259   struct olsr_telnet_session *telnet_session;
260   struct olsr_telnet_cleanup *handler, *it;
261
262   /* get telnet session pointer */
263   telnet_session = (struct olsr_telnet_session *)session;
264
265   /* stop continuous commands */
266   olsr_telnet_stop(&telnet_session->data);
267
268   /* call all cleanup handlers */
269   list_for_each_element_safe(&telnet_session->data.cleanup_list, handler, node, it) {
270     /* remove from list first */
271     olsr_telnet_remove_cleanup(handler);
272
273     /* after this command the handler pointer might not be valid anymore */
274     handler->cleanup_handler(handler);
275   }
276 }
277
278 /**
279  * Create error string for telnet session
280  * @param session pointer to TCP stream
281  * @param error TCP error code to generate
282  */
283 static void
284 _cb_telnet_create_error(struct olsr_stream_session *session,
285     enum olsr_stream_errors error) {
286   switch(error) {
287     case STREAM_REQUEST_FORBIDDEN:
288       /* no message */
289       break;
290     case STREAM_REQUEST_TOO_LARGE:
291       abuf_puts(&session->out, "Input buffer overflow, ending connection\n");
292       break;
293     case STREAM_SERVICE_UNAVAILABLE:
294       abuf_puts(&session->out, "Telnet service unavailable, too many sessions\n");
295       break;
296   }
297 }
298
299 /* handle clean call of stop handler */
300 static void
301 _call_stop_handler(struct olsr_telnet_data *data) {
302   void (*stop_handler)(struct olsr_telnet_data *);
303
304   if (data->stop_handler) {
305     stop_handler = data->stop_handler;
306     data->stop_handler = NULL;
307     stop_handler(data);
308   }
309 }
310
311 /**
312  * Handler for receiving data from telnet session
313  * @param session pointer to TCP session
314  * @return TCP session state
315  */
316 static enum olsr_stream_session_state
317 _cb_telnet_receive_data(struct olsr_stream_session *session) {
318   static const char defaultCommand[] = "/link/neigh/topology/hna/mid/routes";
319   static char tmpbuf[128];
320
321   struct olsr_telnet_session *telnet_session;
322   enum olsr_telnet_result cmd_result;
323   char *eol;
324   int len;
325   bool processedCommand = false, chainCommands = false;
326
327   /* get telnet session pointer */
328   telnet_session = (struct olsr_telnet_session *)session;
329
330   /* loop over input */
331   while (abuf_getlen(&session->in) > 0) {
332     char *para = NULL, *cmd = NULL, *next = NULL;
333
334     /* search for end of line */
335     eol = memchr(abuf_getptr(&session->in), '\n', abuf_getlen(&session->in));
336
337     if (eol == NULL) {
338       break;
339     }
340
341     /* terminate line with a 0 */
342     if (eol != abuf_getptr(&session->in) && eol[-1] == '\r') {
343       eol[-1] = 0;
344     }
345     *eol++ = 0;
346
347     /* handle line */
348     OLSR_DEBUG(LOG_TELNET, "Interactive console: %s\n", abuf_getptr(&session->in));
349     cmd = abuf_getptr(&session->in);
350     processedCommand = true;
351
352     /* apply default command */
353     if (strcmp(cmd, "/") == 0) {
354       strcpy(tmpbuf, defaultCommand);
355       cmd = tmpbuf;
356     }
357
358     if (cmd[0] == '/') {
359       cmd++;
360       chainCommands = true;
361     }
362     while (cmd) {
363       len = abuf_getlen(&session->out);
364
365       /* handle difference between multicommand and singlecommand mode */
366       if (chainCommands) {
367         next = strchr(cmd, '/');
368         if (next) {
369           *next++ = 0;
370         }
371       }
372       para = strchr(cmd, ' ');
373       if (para != NULL) {
374         *para++ = 0;
375       }
376
377       /* if we are doing continous output, stop it ! */
378       _call_stop_handler(&telnet_session->data);
379
380       if (strlen(cmd) != 0) {
381         OLSR_DEBUG(LOG_TELNET, "Processing telnet command: '%s' '%s'",
382             cmd, para);
383
384         telnet_session->data.command = cmd;
385         telnet_session->data.parameter = para;
386         cmd_result = _telnet_handle_command(&telnet_session->data);
387         switch (cmd_result) {
388           case TELNET_RESULT_ACTIVE:
389             break;
390           case TELNET_RESULT_CONTINOUS:
391             telnet_session->data.show_echo = false;
392             break;
393           case TELNET_RESULT_INTERNAL_ERROR:
394             abuf_setlen(&session->out, len);
395             abuf_appendf(&session->out,
396                 "Error in autobuffer during command '%s'.\n", cmd);
397             break;
398           case _TELNET_RESULT_UNKNOWN_COMMAND:
399             abuf_setlen(&session->out, len);
400             abuf_appendf(&session->out, "Error, unknown command '%s'\n", cmd);
401             break;
402           case TELNET_RESULT_QUIT:
403             return STREAM_SESSION_SEND_AND_QUIT;
404         }
405         /* put an empty line behind each command */
406         if (telnet_session->data.show_echo) {
407           abuf_puts(&session->out, "\n");
408         }
409       }
410       cmd = next;
411     }
412
413     /* remove line from input buffer */
414     abuf_pull(&session->in, eol - abuf_getptr(&session->in));
415
416     if (abuf_getptr(&session->in)[0] == '/') {
417       /* end of multiple command line */
418       return STREAM_SESSION_SEND_AND_QUIT;
419     }
420   }
421
422   /* reset timeout */
423   olsr_stream_set_timeout(session, telnet_session->data.timeout_value);
424
425   /* print prompt */
426   if (processedCommand && session->state == STREAM_SESSION_ACTIVE
427       && telnet_session->data.show_echo) {
428     abuf_puts(&session->out, "> ");
429   }
430
431   return STREAM_SESSION_ACTIVE;
432 }
433
434 /**
435  * Helper function to call telnet command handler
436  * @param data pointer to telnet data
437  * @return telnet command result
438  */
439 static enum olsr_telnet_result
440 _telnet_handle_command(struct olsr_telnet_data *data) {
441   struct olsr_telnet_command *cmd;
442 #if !defined(REMOVE_LOG_INFO)
443   struct netaddr_str buf;
444 #endif
445   cmd = _check_telnet_command(data, data->command, NULL);
446   if (cmd == NULL) {
447     return _TELNET_RESULT_UNKNOWN_COMMAND;
448   }
449
450   OLSR_INFO(LOG_TELNET, "Executing command from %s: %s %s",
451       netaddr_to_string(&buf, data->remote), data->command,
452       data->parameter == NULL ? "" : data->parameter);
453   return cmd->handler(data);
454 }
455
456 /**
457  * Checks for existing (and allowed) telnet command.
458  * Either name or cmd should be NULL, but not both.
459  * @param data pointer to telnet data
460  * @param name pointer to command name (might be NULL)
461  * @param cmd pointer to telnet command object (might be NULL)
462  * @return telnet command object or NULL if not found or forbidden
463  */
464 static struct olsr_telnet_command *
465 _check_telnet_command(struct olsr_telnet_data *data,
466     const char *name, struct olsr_telnet_command *cmd) {
467 #if !defined(REMOVE_LOG_DEBUG)
468   struct netaddr_str buf;
469 #endif
470
471   if (cmd == NULL) {
472     cmd = avl_find_element(&telnet_cmd_tree, name, cmd, node);
473     if (cmd == NULL) {
474       return cmd;
475     }
476   }
477   if (cmd->acl == NULL) {
478     return cmd;
479   }
480
481   if (!olsr_acl_check_accept(cmd->acl, data->remote)) {
482     OLSR_DEBUG(LOG_TELNET, "Blocked telnet command '%s' to '%s' because of acl",
483         cmd->command, netaddr_to_string(&buf, data->remote));
484     return NULL;
485   }
486   return cmd;
487 }
488
489 /**
490  * Telnet command 'quit'
491  * @param data pointer to telnet data
492  * @return telnet command result
493  */
494 static enum olsr_telnet_result
495 _cb_telnet_quit(struct olsr_telnet_data *data __attribute__((unused))) {
496   return TELNET_RESULT_QUIT;
497 }
498
499 /**
500  * Telnet command 'help'
501  * @param data pointer to telnet data
502  * @return telnet command result
503  */
504 static enum olsr_telnet_result
505 _cb_telnet_help(struct olsr_telnet_data *data) {
506   struct olsr_telnet_command *ptr, *iterator;
507
508   if (data->parameter != NULL && data->parameter[0] != 0) {
509     ptr = _check_telnet_command(data, data->parameter, NULL);
510     if (ptr == NULL) {
511       abuf_appendf(data->out, "No help text found for command: %s\n", data->parameter);
512       return TELNET_RESULT_ACTIVE;
513     }
514
515     if (ptr->help_handler) {
516       ptr->help_handler(data);
517     }
518     else {
519       if (abuf_appendf(data->out, "%s", ptr->help) < 0) {
520         return TELNET_RESULT_INTERNAL_ERROR;
521       }
522     }
523     return TELNET_RESULT_ACTIVE;
524   }
525
526   if (abuf_puts(data->out, "Known commands:\n") < 0) {
527     return TELNET_RESULT_INTERNAL_ERROR;
528   }
529
530   FOR_ALL_TELNET_COMMANDS(ptr, iterator) {
531     if (_check_telnet_command(data, NULL, ptr)) {
532       if (abuf_appendf(data->out, "  %s\n", ptr->command) < 0) {
533         return TELNET_RESULT_INTERNAL_ERROR;
534       }
535     }
536   }
537
538   if (abuf_puts(data->out, "Use 'help <command> to see a help text for one command\n") < 0) {
539     return TELNET_RESULT_INTERNAL_ERROR;
540   }
541   return TELNET_RESULT_ACTIVE;
542 }
543
544 /**
545  * Telnet command 'echo'
546  * @param data pointer to telnet data
547  * @return telnet command result
548  */
549 static enum olsr_telnet_result
550 _cb_telnet_echo(struct olsr_telnet_data *data) {
551
552   if (abuf_appendf(data->out, "%s\n",
553       data->parameter == NULL ? "" : data->parameter) < 0) {
554     return TELNET_RESULT_INTERNAL_ERROR;
555   }
556   return TELNET_RESULT_ACTIVE;
557 }
558
559 /**
560  * Telnet command 'timeout'
561  * @param data pointer to telnet data
562  * @return telnet command result
563  */
564 static enum olsr_telnet_result
565 _cb_telnet_timeout(struct olsr_telnet_data *data) {
566   if (data->parameter == NULL) {
567     data->timeout_value = 0;
568   }
569   else {
570     data->timeout_value = (uint32_t)strtoul(data->parameter, NULL, 10) * 1000;
571   }
572   return TELNET_RESULT_ACTIVE;
573 }
574
575 /**
576  * Stop handler for repeating telnet commands
577  * @param data pointer to telnet data
578  */
579 static void
580 _cb_telnet_repeat_stophandler(struct olsr_telnet_data *data) {
581   olsr_timer_stop((struct olsr_timer_entry *)data->stop_data[0]);
582   free(data->stop_data[0]);
583   free(data->stop_data[1]);
584
585   data->stop_handler = NULL;
586   data->stop_data[0] = NULL;
587   data->stop_data[1] = NULL;
588   data->stop_data[2] = NULL;
589 }
590
591 /**
592  * Timer event handler for repeating telnet commands
593  * @param ptr pointer to custom data
594  */
595 static void
596 _cb_telnet_repeat_timer(void *ptr) {
597   struct olsr_telnet_data *telnet_data = ptr;
598   struct olsr_telnet_session *session;
599
600   /* set command/parameter with repeat settings */
601   telnet_data->command = telnet_data->stop_data[1];
602   telnet_data->parameter = telnet_data->stop_data[2];
603
604   if (_telnet_handle_command(telnet_data) != TELNET_RESULT_ACTIVE) {
605     _call_stop_handler(telnet_data);
606   }
607
608   /* reconstruct original session pointer */
609   session = container_of(telnet_data, struct olsr_telnet_session, data);
610   olsr_stream_flush(&session->session);
611 }
612
613 /**
614  * Telnet command 'repeat'
615  * @param data pointer to telnet data
616  * @return telnet command result
617  */
618 static enum olsr_telnet_result
619 _cb_telnet_repeat(struct olsr_telnet_data *data) {
620   struct olsr_timer_entry *timer;
621   int interval = 0;
622   char *ptr = NULL;
623
624   if (data->stop_handler) {
625     abuf_puts(data->out, "Error, you cannot stack continous output commands\n");
626     return TELNET_RESULT_ACTIVE;
627   }
628
629   if (data->parameter == NULL || (ptr = strchr(data->parameter, ' ')) == NULL) {
630     abuf_puts(data->out, "Missing parameters for repeat\n");
631     return TELNET_RESULT_ACTIVE;
632   }
633
634   ptr++;
635
636   interval = atoi(data->parameter);
637
638   timer = calloc(1, sizeof(*timer));
639   if (timer == NULL) {
640     return TELNET_RESULT_INTERNAL_ERROR;
641   }
642
643   timer->timer_cb_context = data;
644   timer->timer_info = &_telnet_repeat_timerinfo;
645   olsr_timer_start(timer, interval * 1000);
646
647   data->stop_handler = _cb_telnet_repeat_stophandler;
648   data->stop_data[0] = timer;
649   data->stop_data[1] = strdup(ptr);
650   data->stop_data[2] = NULL;
651
652   /* split command/parameter and remember it */
653   ptr = strchr(data->stop_data[1], ' ');
654   if (ptr != NULL) {
655     /* found a parameter */
656     *ptr++ = 0;
657     data->stop_data[2] = ptr;
658   }
659
660   /* start command the first time */
661   data->command = data->stop_data[1];
662   data->parameter = data->stop_data[2];
663
664   if (_telnet_handle_command(data) != TELNET_RESULT_ACTIVE) {
665     _call_stop_handler(data);
666   }
667
668   return TELNET_RESULT_CONTINOUS;
669 }
670
671 /**
672  * Telnet command 'version'
673  * @param data pointer to telnet data
674  * @return telnet command result
675  */
676 static enum olsr_telnet_result
677 _cb_telnet_version(struct olsr_telnet_data *data) {
678   olsr_log_printversion(data->out);
679   return TELNET_RESULT_ACTIVE;
680 }
681
682 /**
683  * Telnet command 'plugin'
684  * @param data pointer to telnet data
685  * @return telnet command result
686  */
687 static enum olsr_telnet_result
688 _cb_telnet_plugin(struct olsr_telnet_data *data) {
689   struct olsr_plugin *plugin, *iterator;
690   const char *plugin_name = NULL;
691
692   if (data->parameter == NULL || strcasecmp(data->parameter, "list") == 0) {
693     if (abuf_puts(data->out, "Plugins:\n") < 0) {
694       return TELNET_RESULT_INTERNAL_ERROR;
695     }
696     OLSR_FOR_ALL_PLUGIN_ENTRIES(plugin, iterator) {
697       if (abuf_appendf(data->out, " %-30s\t%s\t%s\n",
698           plugin->name, olsr_plugins_is_enabled(plugin) ? "enabled" : "",
699           olsr_plugins_is_static(plugin) ? "static" : "") < 0) {
700         return TELNET_RESULT_INTERNAL_ERROR;
701       }
702     }
703     return TELNET_RESULT_ACTIVE;
704   }
705
706   plugin_name = strchr(data->parameter, ' ');
707   if (plugin_name == NULL) {
708     if (abuf_appendf(data->out, "Error, missing or unknown parameter\n") < 0) {
709       return TELNET_RESULT_INTERNAL_ERROR;
710     }
711     return TELNET_RESULT_ACTIVE;
712   }
713
714   /* skip whitespaces */
715   while (isspace(*plugin_name)) {
716     plugin_name++;
717   }
718
719   plugin = olsr_plugins_get(plugin_name);
720   if (str_hasnextword(data->parameter, "load") == NULL) {
721     if (plugin != NULL) {
722       abuf_appendf(data->out, "Plugin %s already loaded\n", plugin_name);
723       return TELNET_RESULT_ACTIVE;
724     }
725     plugin = olsr_plugins_load(plugin_name);
726     if (plugin != NULL) {
727       abuf_appendf(data->out, "Plugin %s successfully loaded\n", plugin_name);
728     }
729     else {
730       abuf_appendf(data->out, "Could not load plugin %s\n", plugin_name);
731     }
732     return TELNET_RESULT_ACTIVE;
733   }
734
735   if (plugin == NULL) {
736     if (abuf_appendf(data->out,
737         "Error, could not find plugin '%s'.\n", plugin_name) < 0) {
738       return TELNET_RESULT_INTERNAL_ERROR;
739     }
740     return TELNET_RESULT_ACTIVE;
741   }
742   if (str_hasnextword(data->parameter, "activate") == NULL) {
743     if (olsr_plugins_is_enabled(plugin)) {
744       abuf_appendf(data->out, "Plugin %s already active\n", plugin_name);
745     }
746     else {
747       if (olsr_plugins_enable(plugin)) {
748         abuf_appendf(data->out, "Could not activate plugin %s\n", plugin_name);
749       }
750       else {
751         abuf_appendf(data->out, "Plugin %s successfully activated\n", plugin_name);
752       }
753     }
754   }
755   else if (str_hasnextword(data->parameter, "deactivate") == NULL) {
756     if (!olsr_plugins_is_enabled(plugin)) {
757       abuf_appendf(data->out, "Plugin %s is not active\n", plugin_name);
758     }
759     else {
760       if (olsr_plugins_disable(plugin)) {
761         abuf_appendf(data->out, "Could not deactivate plugin %s\n", plugin_name);
762       }
763       else {
764         abuf_appendf(data->out, "Plugin %s successfully deactivated\n", plugin_name);
765       }
766     }
767   }
768   else if (str_hasnextword(data->parameter, "unload") == NULL) {
769     if (olsr_plugins_is_static(plugin)) {
770       abuf_appendf(data->out, "Plugin %s is static and cannot be unloaded\n", plugin_name);
771     }
772     else {
773       if (olsr_plugins_unload(plugin)) {
774         abuf_appendf(data->out, "Could not unload plugin %s\n", plugin_name);
775       }
776       else {
777         abuf_appendf(data->out, "Plugin %s successfully unloaded\n", plugin_name);
778       }
779     }
780   }
781   else {
782     abuf_appendf(data->out, "Unknown command '%s %s %s'.\n",
783         data->command, data->parameter, plugin_name);
784   }
785   return TELNET_RESULT_ACTIVE;
786 }