/*
* menu.c
* This file is part of lcdexec, an LCDproc client.
*
* This file is released under the GNU General Public License. Refer to the
* COPYING file distributed with this package.
*
* Copyright (c) 2002, Joris Robijn
* Copyright (c) 2006, Peter Marschall
*/
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "shared/str.h"
#include "shared/report.h"
#include "shared/configfile.h"
#include "shared/sockets.h"
#include "menu.h"
/* recursively read the menu hierarchy */
MenuEntry *menu_read(MenuEntry *parent, const char *name)
{
static int id = 0;
if (config_has_section(name)) {
MenuEntry *me = calloc(1, sizeof(MenuEntry));
if (me == NULL)
return NULL;
// set common entries
me->id = id++;
me->name = strdup(name);
if (me->name == NULL) {
//menu_free(me);
return NULL;
}
me->displayname = strdup(config_get_string(name, "DisplayName", 0, name));
if (me->name == NULL) {
//menu_free(me);
return NULL;
}
me->entries = NULL;
me->next = NULL;
me->command = NULL;
if (config_get_string(name, "Entry", 0, NULL) != NULL) {
MenuEntry **addr = &me->entries;
const char *entryname;
int index = 0;
// it is a sub-menu
me->type = menu;
while ((entryname = config_get_string(name, "Entry", index++, NULL)) != NULL) {
MenuEntry *entry = menu_read(me, entryname);
if (entry == NULL) {
//menu_free(me);
return NULL;
}
*addr = entry;
addr = &entry->next;
}
}
else if (config_get_string(name, "Exec", 0, NULL) != NULL) {
// it's a command to execute
me->type = exec;
me->command = strdup(config_get_string(name, "Exec", 0, ""));
if (me->command == NULL) {
//menu_free(me);
return NULL;
}
}
else {
//menu_free(me);
return NULL;
}
return me;
}
return NULL;
}
/* create LCDproc commands for the menu entry hierarchy and send it to the server */
int menu_sock_send(MenuEntry *me, MenuEntry *parent, int sock)
{
if ((me != NULL) && (sock > 0)) {
char parent_id[12];
// set parent_id depending on the parent given
if ((parent != NULL) && (parent->id != 0))
sprintf(parent_id, "%d", parent->id);
else
strcpy(parent_id, "");
switch (me->type) {
MenuEntry *entry;
case menu:
// don't create a separate entry for the main menu
if ((parent != NULL) && (me->id != 0)) {
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" menu \"%s\"\n",
parent_id, me->id, me->displayname) < 0)
return -1;
}
// recursively do it for the menu's sub-menus
for (entry = me->entries; entry != NULL; entry = entry->next) {
if (menu_sock_send(entry, me, sock) < 0)
return -1;
}
break;
case exec:
if (sock_printf(sock, "menu_add_item \"%s\" \"%d\" action \"%s\"\n",
parent_id, me->id, me->displayname) < 0)
return -1;
if (sock_printf(sock, "menu_set_item \"%s\" \"%d\" -menu_result quit\n",
parent_id, me->id) < 0)
return -1;
break;
case unknown:
default:
return -1;
}
return 0;
}
return -1;
}
/* find menu entry by its id */
MenuEntry *menu_find_by_id(MenuEntry *me, int id)
{
if (me != NULL) {
if (me->id == id)
return me;
if (me->type == menu) {
MenuEntry *entry;
for (entry = me->entries; entry != NULL; entry = entry->next) {
MenuEntry *result = menu_find_by_id(entry, id);
if (result != NULL)
return result;
}
}
}
return NULL;
}
/* return command of a menu entry */
const char *menu_command(MenuEntry *me)
{
if ((me != NULL) && (me->type == exec))
return me->command;
return NULL;
}
/* free menu entry hierarchy */
void menu_free(MenuEntry *me)
{
if (me != NULL) {
switch (me->type) {
MenuEntry *entry;
case menu:
for (entry = me->entries; entry != NULL; ) {
MenuEntry *old = entry;
entry = entry->next;
old->next = NULL;
menu_free(old);
}
me->entries = NULL;
break;
case exec:
if (me->command != NULL)
free(me->command);
me->command = NULL;
break;
case unknown:
default:
break;
}
if (me->name != NULL)
free(me->name);
me->name = NULL;
if (me->displayname != NULL)
free(me->displayname);
me->displayname = NULL;
me->type = unknown;
free(me);
}
}
#if defined(DEBUG)
/* dump menu entry hierarchy to screen */
void menu_dump(MenuEntry *me)
{
if (me != NULL) {
report(RPT_DEBUG, "# menu ID: %d", me->id);
report(RPT_DEBUG, "[%s]", me->name);
if (me->displayname != NULL)
report(RPT_DEBUG, "DisplayName=\"%s\"", me->displayname);
switch (me->type) {
MenuEntry *entry;
case menu:
for (entry = me->entries; entry != NULL; entry = entry->next)
report(RPT_DEBUG, "Entry=%s", entry->name);
break;
case exec:
report(RPT_DEBUG, "Exec=\"%s\"", me->command);
break;
case unknown:
default:
report(RPT_DEBUG, "ERROR: unknown menu entry type");
break;
}
report(RPT_DEBUG, "");
// recursively walk through sub-menus
if (me->type == menu) {
MenuEntry *entry;
for (entry = me->entries; entry != NULL; entry = entry->next)
menu_dump(entry);
}
}
}
#endif
/* EOF */
syntax highlighted by Code2HTML, v. 0.9.1