[ekg2-commit] ekg2: commands.c (HEAD) [darkjames]

CVS commit cvs w toxygen.net
Pią, 2 Lis 2007, 00:24:11 CET


Module name:	ekg2
Changes by:	darkjames	2007-11-02 00:24:09

Modified files:
	commands.c

Log message:
fix content of ekg/commands.c

Index: commands.c
===================================================================
RCS file: /home/cvs/ekg2/ekg/commands.c,v
diff -d -u -r1.295 -r1.296
--- commands.c	31 Oct 2007 00:22:08 -0000	1.295
+++ commands.c	1 Nov 2007 23:24:08 -0000	1.296
@@ -1,4 +1,1836 @@
-cmd_quit)
+/* $Id$ */
+
+/*
+ *  (C) Copyright 2001-2005 Wojtek Kaniewski <wojtekka w irc.pl>
+ *                          Robert J. Woźny <speedy w ziew.org>
+ *                          Paweł Maziarz <drg w infomex.pl>
+ *                          Wojciech Bojdoł <wojboj w htc.net.pl>
+ *                          Piotr Wysocki <wysek w linux.bydg.org>
+ *                          Dawid Jarosz <dawjar w poczta.onet.pl>
+ *                          Piotr Domagalski <szalik w szalik.net>
+ *                          Kuba Kowalski <qbq w kofeina.net>
+ *			    Piotr Kupisiewicz <deli w rzepaknet.us>
+ *			    Leszek Krupiński <leafnode w wafel.com>
+ *			    Adam Mikuta <adamm w ekg2.org>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License Version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "ekg2-config.h"
+#include "win32.h"
+
+#ifndef __FreeBSD__
+#define _XOPEN_SOURCE 600
+#define __EXTENSIONS__
+#endif
+
+#define _BSD_SOURCE
+
+#include <sys/types.h>
+
+#ifndef NO_POSIX_SYSTEM
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#endif
+
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#ifndef NO_POSIX_SYSTEM
+#include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifndef NO_POSIX_SYSTEM
+#include <sys/utsname.h>
+#endif
+
+#ifdef __sun
+#include <procfs.h>
+#endif
+
+#ifdef __FreeBSD__
+# include <kvm.h>		/* kvm_ funcs */
+# include <limits.h>		/* _POSIX2_LINE_MAX */
+# include <sys/param.h>
+# include <sys/sysctl.h>	/* KERN_PROC_PID */
+# include <sys/user.h>
+#endif
+
+#include "commands.h"
+#include "debug.h"
+#include "events.h"
+#include "configfile.h"
+#include "dynstuff.h"
+#include "log.h"
+#include "metacontacts.h"
+#include "msgqueue.h"
+#include "protocol.h"
+#include "sessions.h"
+#ifndef HAVE_STRLCAT
+#  include "compat/strlcat.h"
+#endif
+#ifndef HAVE_STRLCPY
+#  include "compat/strlcpy.h"
+#endif
+#include "stuff.h"
+#include "themes.h"
+#include "vars.h"
+#include "userlist.h"
+#include "scripts.h"
+#include "windows.h"
+#include "xmalloc.h"
+
+#include "queries.h"
+
+char *send_nicks[SEND_NICKS_MAX] = { NULL };
+int send_nicks_count = 0, send_nicks_index = 0;
+static int quit_command = 0;
+
+list_t commands = NULL;
+list_t *commands_lock = NULL;
+
+/*
+ * match_arg()
+ *
+ * sprawdza, czy dany argument funkcji pasuje do podanego.
+ */
+int match_arg(const char *arg, char shortopt, const char *longopt, int longoptlen)
+{
+	if (!arg || *arg != '-')
+		return 0;
+
+	arg++;
+	if (*arg == '-') {
+		int len = xstrlen(++arg);
+
+		if (longoptlen > len)
+			len = longoptlen;
+
+		return !xstrncmp(arg, longopt, len);
+	}
+	return (*arg == shortopt) && (*(arg + 1) == 0);
+}
+
+/*
+ * tabnick_add()
+ *
+ * dodaje do listy nicków dopełnianych automagicznie tabem.
+ */
+void tabnick_add(const char *nick)
+{
+	int i;
+
+	for (i = 0; i < send_nicks_count; i++)
+		if (send_nicks[i] && !xstrcmp(nick, send_nicks[i])) {
+			tabnick_remove(nick);
+			break;
+		}
+
+	if (send_nicks_count == SEND_NICKS_MAX) {
+		xfree(send_nicks[SEND_NICKS_MAX - 1]);
+		send_nicks_count--;
+	}
+
+	for (i = send_nicks_count; i > 0; i--)
+		send_nicks[i] = send_nicks[i - 1];
+
+	if (send_nicks_count != SEND_NICKS_MAX)
+		send_nicks_count++;
+	
+	send_nicks[0] = xstrdup(nick);
+}
+
+/*
+ * tabnick_remove()
+ *
+ * usuwa z listy dopełnianych automagicznie tabem.
+ */
+void tabnick_remove(const char *nick)
+{
+	int i, j;
+
+	for (i = 0; i < send_nicks_count; i++) {
+		if (send_nicks[i] && !xstrcmp(send_nicks[i], nick)) {
+			xfree(send_nicks[i]);
+
+			for (j = i + 1; j < send_nicks_count; j++)
+				send_nicks[j - 1] = send_nicks[j];
+
+			send_nicks_count--;
+			send_nicks[send_nicks_count] = NULL;
+
+			break;
+		}
+	}
+}
+
+/*
+ * tabnick_flush()
+ *
+ * czyści listę nicków dopełnianych tabem.
+ */
+void tabnick_flush()
+{
+	int i;
+
+	for (i = 0; i < send_nicks_count; i++) {
+		xfree(send_nicks[i]);
+		send_nicks[i] = NULL;
+	}
+
+	send_nicks_count = 0;
+	send_nicks_index = 0;
+}
+
+/*
+ * command_find()
+ *
+ * szuka podanej komendy.
+ */
+command_t *command_find(const char *name)
+{
+        list_t l;
+
+        if (!name)
+                return NULL;
+        for (l = commands; l; l = l->next) {
+                command_t *c = l->data;
+
+                if (!xstrcasecmp(c->name, name)) {
+                        return c;
+		}
+        }
+        return NULL;
+}
+
+
+static COMMAND(cmd_tabclear)
+{
+	int i;
+
+	if (!params[0]) {
+		tabnick_flush();
+		return 0;
+	}
+
+	if (match_arg(params[0], 'o', ("offline"), 2)) {
+		for (i = 0; i < send_nicks_count; i++) {
+			userlist_t *u = NULL;
+
+			if (send_nicks[i])
+				u = userlist_find(session, send_nicks[i]);
+
+			/* I think we should also remove errors and likes here
+			 * if I'm wrong, change the > to == */
+			if (!u || (u->status > EKG_STATUS_NA))
+				continue;
+
+			tabnick_remove(send_nicks[i]);
+		}
+
+		return 0;
+	}
+
+	printq("invalid_params", name);
+
+	return -1;
+}
+
+/* XXX, rewritten, need checking */
+COMMAND(cmd_add) {
+	int params_free = 0;	/* zmieniliśmy params[] i trzeba zwolnić */
+	int result = 0;
+	userlist_t *u = NULL;
+	
+	/* XXX, just in case? */
+	if (!target)
+		target = window_current->target;
+
+	/* XXX, check this damn session_current. */
+	if (!session)
+		session = session_current;
+
+	if (!session)
+		return -1;
+	
+	/* If we didn't have params[1] and we params[0] isn't option (for example not --find) and we have target 
+	 * 	get uid from current window, get nickname from params[0]
+	 *
+	 * 	Code for getting more options from params[1] && params[2] were senseless, cause we have !params[1] ;(
+	 */
+	if (params[0][0] != '-' && !params[1] && target) {
+		const char *name = params[0];
+
+		params_free = 1;
+		params = xmalloc(3 * sizeof(char *));
+		params[0] = target;
+		params[1] = name;
+/* 		params[2] = NULL */
+	}
+
+	/* if we have passed -f [lastfound] then get uid, nickname and other stuff from searches... */
+	/* if params[1] passed than it should be used as nickname */
+
+	/* XXX, we need to make it session-visible only.. or at least protocol-visible only.
+	 * 	cause we maybe implement it in jabber */
+	if (match_arg(params[0], 'f', ("find"), 2)) {
+		const char *nickname;
+
+		if (!last_search_uid || (!last_search_nickname && !params[1])) {
+			printq("search_no_last");
+			return -1;
+		}
+
+		nickname = last_search_nickname ? strip_spaces(last_search_nickname) : params[1];
+
+		if (nickname && nickname[0] == '\0') 
+			nickname = params[1];
+
+		if (!nickname) {
+			printq("search_no_last_nickname");
+			return -1;
+		}
+
+		params_free = 1;
+
+		params = xmalloc(4 * sizeof(char *));
+		params[0] = last_search_uid;
+		params[1] = nickname;
+		/* construct params[2] -f FIRST_NAME -l LAST_NAME */
+		params[2] = saprintf("-f \"%s\" -l \"%s\"", 
+				((last_search_first_name) ? last_search_first_name : ("")), 
+				((last_search_last_name) ? last_search_last_name : ("")));
+/*		params[3] = NULL; */
+	}
+
+	if (!params[1]) {
+		printq("not_enough_params", name);
+		result = -1;
+		goto cleanup;
+	}
+
+
+	if (!valid_plugin_uid(session->plugin, params[0])) {
+		printq("invalid_uid");
+		result = -1;
+		goto cleanup;
+	}
+
+	if (!valid_nick(params[1])) {
+		printq("invalid_nick");
+		result = -1;
+		goto cleanup;
+	}
+
+	/* XXX, parse params[2] */
+
+	if (((u = userlist_find(session, params[0])) && u->nickname) || ((u = userlist_find(session, params[1])) && u->nickname)) {
+		if (!xstrcasecmp(params[1], u->nickname) && !xstrcasecmp(params[0], u->uid))
+			printq("user_exists", params[1], session_name(session));
+		else
+			printq("user_exists_other", params[1], format_user(session, u->uid), session_name(session));
+
+		result = -1;
+		goto cleanup;
+	}
+
+	/* ktoś był tylko ignorowany/blokowany, nadajmy mu nazwę */
+	if (u) {
+		xfree(u->nickname);
+		u->nickname = xstrdup(params[1]);
+	}
+
+	if (u || userlist_add(session, params[0], params[1])) {
+		char *uid = xstrdup(params[0]);
+
+		query_emit_id(NULL, USERLIST_ADDED, &uid, &params[1], &quiet);
+                query_emit_id(NULL, ADD_NOTIFY, &session->uid, &uid);
+                xfree(uid);
+
+		printq("user_added", params[1], session_name(session));
+
+		tabnick_remove(params[0]);
+		config_changed = 1;
+
+	}
+
+cleanup:
+	if (params_free) {
+		xfree((char*) params[2]);
+		xfree(params);
+	}
+
+	return result;
+}
+
+static COMMAND(cmd_alias)
+{
+	if (match_arg(params[0], 'a', ("add"), 2)) {
+		if (!params[1] || !xstrchr(params[1], ' ')) {
+			printq("not_enough_params", name);
+			return -1;
+		}
+
+		if (!alias_add(params[1], quiet, 0)) {
+			config_changed = 1;
+			return 0;
+		}
+
+		return -1;
+	}
+
+	if (match_arg(params[0], 'A', ("append"), 2)) {
+		if (!params[1] || !xstrchr(params[1], ' ')) {
+			printq("not_enough_params", name);
+			return -1;
+		}
+
+		if (!alias_add(params[1], quiet, 1)) {
+			config_changed = 1;
+			return 0;
+		}
+
+		return -1;
+	}
+
+	if (match_arg(params[0], 'd', ("del"), 2)) {
+		int ret;
+
+		if (!params[1]) {
+			printq("not_enough_params", name);
+			return -1;
+		}
+
+		if (!xstrcmp(params[1], "*"))
+			ret = alias_remove(NULL, quiet);
+		else {
+			ret = alias_remove(params[1], quiet);
+		}
+
+		if (!ret) {
+			config_changed = 1;
+			return 0;
+		}
+
+		return -1;
+	}
+	
+	if (!params[0] || match_arg(params[0], 'l', ("list"), 2) || params[0][0] != '-') {
+		list_t l;
+		int count = 0;
+		const char *aname = NULL;
+
+		if (params[0] && match_arg(params[0], 'l', ("list"), 2))
+			aname = params[1];
+		else if (params[0])
+			aname = params[0];
+
+		for (l = aliases; l; l = l->next) {
+			struct alias *a = l->data;
+			list_t m;
+			int first = 1, i;
+			char *tmp;
+			
+			if (aname && xstrcasecmp(aname, a->name))
+				continue;
+
+			tmp = xcalloc(xstrlen(a->name) + 1, sizeof(char));
+
+			for (i = 0; i < xstrlen(a->name); i++)
+				xstrcat(tmp, " ");
+
+			for (m = a->commands; m; m = m->next) {
+				printq((first) ? "aliases_list" : "aliases_list_next", a->name, (char *) m->data, tmp);
+				first = 0;
+				count++;
+			}
+
+			xfree(tmp);
+		}
+
+		if (!count) {
+			if (aname) {
+				printq("aliases_noexist", aname);
+				return -1;
+			}
+
+			printq("aliases_list_empty");
+		}
+		return 0;
+	}
+
+	printq("invalid_params", name);
+
+	return -1;
+}
+
+static COMMAND(cmd_status) {
+	struct tm *t;
+	time_t n;
+	int now_days;
+
+	char buf1[100] = { '\0' };
+	const char *format;
+	session_t *s = NULL;
+
+	printq("show_status_header");
+
+	s = params[0] ? session_find(params[0]) : session;
+
+	if (params[0] && !s) {
+		printq("invalid_uid", params[0]);
+		return -1;
+	}
+
+	if (config_profile)
+		printq("show_status_profile", config_profile);
+
+	n = time(NULL);
+	t = localtime(&n);
+	now_days = t->tm_yday;
+
+	if (s) {
+		query_emit_id(s->plugin, STATUS_SHOW, &s->uid);
+
+		/* when we connected [s->connected != 0] to server or when we lost last connection [s->connected == 0] [time from s->last_conn] */
+		if (s->last_conn) { 
+			char buf[100] = { '\0' };
+
+			t = localtime(&s->last_conn);
+			format = format_find((t->tm_yday == now_days) ? "show_status_last_conn_event_today" : "show_status_last_conn_event");
+			if (format[0] && !strftime(buf, sizeof(buf), format, t))
+				xstrcpy(buf, "TOOLONG");
+
+			printq((s->connected) ? "show_status_connected_since" : "show_status_disconnected_since", buf);
+		}
+	}
+
+	t = localtime(&ekg_started);
+	format = format_find((t->tm_yday == now_days) ? "show_status_ekg_started_today" : "show_status_ekg_started");
+	if (format[0] && !strftime(buf1, sizeof(buf1), format, t))
+		xstrcpy(buf1, "TOOLONG");
+
+	printq("show_status_ekg_started_since", buf1);
+	printq("show_status_footer");
+
+	return 0;
+}
+
+static COMMAND(cmd_del)
+{
+	userlist_t *u;
+	char *tmp;
+	int del_all = ((params[0] && !xstrcmp(params[0], "*")) ? 1 : 0);
+
+	if (!session)
+		return -1;
+	
+	if (!params[0]) {
+		printq("not_enough_params", name);
+		return -1;
+	}
+
+	if (del_all) {
+		list_t l;
+		for (l = session->userlist; l; ) {
+			userlist_t *u = l->data;
+			char *p0;
+			char *tmp;
+	
+			l = l->next;
+			p0 = xstrdup(u->nickname);
+			tmp = xstrdup(u->uid);
+			query_emit_id(NULL, USERLIST_REMOVED, &p0, &tmp);
+			xfree(tmp);
+			xfree(p0);
+
+			userlist_remove(session, u);
+		}
+
+		printq("user_cleared_list", session_name(session));
+		tabnick_flush();
+		config_changed = 1;
+
+		return 0;
+	}
+
+	if (!(u = userlist_find(session, params[0])) || !u->nickname) {
+		printq("user_not_found", params[0]);
+		return -1;
+	}
+
+	tmp = xstrdup(u->uid);
+	query_emit_id(NULL, USERLIST_REMOVED, &params[0], &tmp);
+	query_emit_id(NULL, REMOVE_NOTIFY, &session->uid, &tmp);
+
+        printq("user_deleted", params[0], session_name(session));
+	xfree(tmp);
+
+	tabnick_remove(u->uid);
+	tabnick_remove(u->nickname);
+
+	config_changed = 1;
+
+	userlist_remove(session, u);
+	
+	return 0;
+}
+
+/**
+ * cmd_exec_info_t is internal structure, containing information about processes started using /exec.
+ */
+typedef struct {
+	char *target;		/**< Target UID, if redirecting output to someone */
+	char *session;		/**< Session UID */
+	int quiet;		/**< Whether to be quiet (i.e. don't print info on exit) */
+	string_t buf;		/**< Buffer */
+} cmd_exec_info_t;
+
+static WATCHER_LINE(cmd_exec_watch_handler)	/* stały */
+{
+	cmd_exec_info_t *i = data;
+	int quiet = (i) ? i->quiet : 0;
+
+	if (!i)
+		return -1;
+
+	if (type == 1) {
+		if (i->buf) {
+			command_exec_format(i->target, session_find(i->session), quiet, ("/ %s"), i->buf->str);
+			string_free(i->buf, 1);
+		}
+		xfree(i->target);
+		xfree(i->session);
+		xfree(i);
+		return 0;
+	}
+
+	if (!i->target) {
+		printq("exec", watch);
+		return 0;
+	}
+
+	if (i->buf) {
+		string_append(i->buf, watch);
+		string_append(i->buf, ("\r\n"));
+	} else {
+		command_exec_format(i->target, session_find(i->session), quiet, ("/ %s"), watch);
+	}
+	return 0;
+}
+
+void cmd_exec_child_handler(child_t *c, int pid, const char *name, int status, void *priv)
+{
+	int quiet = (name && name[0] == '^');
+
+	printq("process_exit", itoa(pid), name, itoa(status));
+}
+
+COMMAND(cmd_exec)
+{
+	list_t l;
+	int pid;
+
+	if (params[0]) {
+		int fd[2] = { 0, 0 }, buf = 0, add_commandline = 0;
+		const char *command = params[0], *target = NULL;
+		char **args = NULL;
+		cmd_exec_info_t *i;
+		watch_t *w;
+
+		if (params[0][0] == '-') {
+			int big_match = 0;
+			args = (char **) params;
+
+			if (match_arg(args[0], 'M', ("MSG"), 2) || (buf = match_arg(args[0], 'B', ("BMSG"), 2)))
+				big_match = add_commandline = 1;
+
+			if (big_match || match_arg(args[0], 'm', ("msg"), 2) || (buf = match_arg(args[0], 'b', ("bmsg"), 2))) {
+				const char *uid;
+
+				if (!args[1] || !args[2]) {
+					printq("not_enough_params", name);
+					return -1;
+				}
+
+				if (!(uid = get_uid(session, args[1]))) {
+					printq("user_not_found", args[1]);
+					return -1;
+				}
+
+				target = uid;
+				command = args[2];
+			} else {
+				printq("invalid_params", name);
+				return -1;
+			}
+		} 
+
+		if (pipe(fd) == -1) {
+			printq("exec_error", strerror(errno));
+			return -1;
+		}
+
+#ifndef NO_POSIX_SYSTEM
+		if (!(pid = fork())) {
+			dup2(open("/dev/null", O_RDONLY), 0);
+			dup2(fd[1], 1);
+			dup2(fd[1], 2);
+
+			close(fd[0]);
+			close(fd[1]);
+
+			execl("/bin/sh", "sh", "-c", (command[0] == '^') ? command + 1 : command, (void *) NULL);
+
+			exit(1);
+		}
+#else
+/* XXX, fork and execute cmd /C $command
+ * MG: I think using explicitly 'cmd /c' is very bad - in win9x we've got command.com instead;
+ *     but AFAIR $COMSPEC should be always defined; if not, we should even use command.com
+ *     (AFAIK newer versions of windows are backwards compatible with this) */
+		pid = -1;
+#endif
+
+		if (pid < 0) {
+			printq("exec_error", strerror(errno));
+			close(fd[0]);
+			close(fd[1]);
+			return -1;
+		}
+	
+		i = xmalloc(sizeof(cmd_exec_info_t));
+		
+		i->quiet = quiet;
+		i->target = xstrdup(target);
+		i->session = xstrdup(session_uid_get(session));
+
+		if (buf)
+			i->buf = string_init(NULL);
+
+		w = watch_add_line(NULL, fd[0], WATCH_READ_LINE, cmd_exec_watch_handler, i);
+
+		if (add_commandline) {
+			char *tmp = format_string(format_find("exec_prompt"), ((command[0] == '^') ? command + 1 : command));
+			string_append(w->buf, tmp);
+			xfree(tmp);
+		}
+
+		fcntl(fd[0], F_SETFL, O_NONBLOCK);
+
+		close(fd[1]);
+		child_add(NULL, pid, command, cmd_exec_child_handler, NULL);
+
+	} else {
+		for (l = children; l; l = l->next) {
+			child_t *c = l->data;
+			
+			printq("process", itoa(c->pid), ((c->name) ? (c->name) : ("?")));
+		}
+
+		if (!children) {
+			printq("no_processes");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * cmd_eval()
+ *
+ * Execute space seperated commands from @a params[0]<br>
+ * If you want add params to command use " " sample: /eval "first_commamnd --first_param --second_param" second_command third_command
+ *
+ * Handler for: <i>/eval</i> command.
+ *
+ * @param params [0] - commands to execute
+ *
+ * @return 0
+ */
+
+static COMMAND(cmd_eval) {
+	int i;
+	char **argv;
+
+	argv = array_make(params[0], (" "), 0, 1, 1);
+	
+	for (i = 0; argv[i]; i++)
+		command_exec(NULL, session, argv[i], 0);
+
+	array_free(argv);
+
+	return 0;
+}
+
+static COMMAND(cmd_for)
+{
+	int for_all = 0;
+
+	if (!xstrcmp(params[1], "*")) 
+		for_all = 1; 
+
+	if (match_arg(params[0], 's', ("sessions"), 2)) {
+		char *param = (char *) params[2];
+		int next_is_for = 0;
+
+		if (param[0] == '/')
+			param++;
+
+		if (!xstrncasecmp(param, name, xstrlen(name)))
+			next_is_for = 1;
+
+		if (for_all) {
+			list_t l;
+			
+			if (!sessions) {
+				printq("session_list_empty");
+				return -2;
+			}
+				
+			for (l = sessions; l; l = l->next) {
+				session_t *s = l->data;
+				char *for_command;
+				
+				if (!s || !s->uid)
+					continue;
+				
+				if (!next_is_for)
+					for_command = format_string(params[2], session_alias_uid(s), s->uid);
+				else
+					for_command = xstrdup(params[2]);
+
+				command_exec(NULL, s, for_command, 0);
+				xfree(for_command);
+			}
+		} else {
+			char **tmp = array_make(params[1], ",", 0, 0, 0);
+			int i;
+			session_t **s;
+	
+			s = xmalloc(sizeof(session_t *) * array_count(tmp));
+			
+			/* first we are checking all of the parametrs */
+			for (i = 0; tmp[i]; i++) {
+				if (!(s[i] = session_find(tmp[i]))) {
+					printq("session_doesnt_exist", tmp[i]);
+					xfree(s);
+					array_free(tmp);
+					return -1;
+				}
+			}		
+			
+			for (i = 0; tmp[i]; i++) {
+				char *for_command;
+				
+				if (!s[i] || !s[i]->uid)
+					continue;
+				
+				if (!next_is_for)
+					for_command = format_string(params[2], session_alias_uid(s[i]), s[i]->uid);
+				else
+					for_command = xstrdup(params[2]);
+
+				command_exec(NULL, s[i], for_command, 0);
+				xfree(for_command);
+			}
+			array_free(tmp);
+			xfree(s);
+		}
+	} else if (match_arg(params[0], 'u', ("users"), 2)) {
+		char *param = (char *) params[2];
+                int next_is_for = 0;
+
+                if (param[0] == '/')
+                        param++;
+
+                if (!xstrncasecmp(param, name, xstrlen(name)))
+                        next_is_for = 1;
+				
+		if (!session) {
+			return -1;
+		}
+
+		if (!session->userlist) {
+			printq("list_empty");
+			return -1;
+		}
+
+		if (for_all) {
+			list_t l;
+
+			for (l = session->userlist; l; l = l->next) {
+				userlist_t *u = l->data;
+				char *for_command;
+
+				if (!u || !u->uid)
+					continue;
+				
+				if (!next_is_for)
+					for_command = format_string(params[2], (u->nickname) ? u->nickname : u->uid, u->uid);
+				else
+					for_command = xstrdup(params[2]);
+
+				command_exec(NULL, session, for_command, 0);
+				xfree(for_command);
+			}
+				
+		} else {
+                        char **tmp = array_make(params[1], ",", 0, 0, 0);
+                        int i;
+                        userlist_t **u;
+
+                        u = xmalloc(sizeof(userlist_t *) * array_count(tmp));
+
+                        /* first we are checking all of the parametrs */
+                        for (i = 0; tmp[i]; i++) {
+                                if (!(u[i] = userlist_find(session, tmp[i]))) {
+                                        printq("user_not_found", tmp[i]);
+					array_free(tmp);
+                                        xfree(u);
+					return -1;
+                                }
+                        }
+
+                        for (i = 0; tmp[i]; i++) {
+                                char *for_command;
+
+                                if (!u[i] || !u[i]->uid)
+                                        continue;
+
+				if (!next_is_for)
+	                                for_command = format_string(params[2], (u[i]->nickname) ? u[i]->nickname : u[i]->uid, u[i]->uid);
+				else
+					for_command = xstrdup(params[2]);
+
+                                command_exec(NULL, session, for_command, 0);
+                                xfree(for_command);
+                        }
+			array_free(tmp);
+                        xfree(u);
+                }
+	} else if (match_arg(params[0], 'w', ("windows"), 2)) {
+                char *param = (char *) params[2];
+                int next_is_for = 0;
+
+                if (param[0] == '/')
+                        param++;
+
+                if (!xstrncasecmp(param, name, xstrlen(name)))
+                        next_is_for = 1;
+
+                if (!windows) {
+			return -1;
+                }
+
+                if (for_all) {
+                        list_t l;
+
+                        for (l = windows; l; l = l->next) {
+                        	window_t *w = l->data;
+                                char *for_command;
+
+                                if (!w || !w->target || !w->session)
+                                        continue;
+
+                                if (!next_is_for)		/* XXX, get_uid(), get_nickname() */
+                                        for_command = format_string(params[2], get_nickname(w->session, w->target), get_uid(w->session, w->target));
+                                else
+                                        for_command = xstrdup(params[2]);
+
+                                command_exec(NULL, w->session, for_command, 0);
+                                xfree(for_command);
+			}
+                 } else {
+                       	char **tmp = array_make(params[1], ",", 0, 0, 0);
+	                int i;
+	                window_t **w;
+
+                        w = xmalloc(sizeof(window_t *) * array_count(tmp));
+
+                        /* first we are checking all of the parametrs */
+                        for (i = 0; tmp[i]; i++) {
+				if (!(w[i] = window_exist(atoi(tmp[i])))) {
+		                        printq("window_doesnt_exist", tmp[i]);
+					array_free(tmp);
+                                        xfree(w);
+					return -1;
+				}
+                        }
+
+                        for (i = 0; tmp[i]; i++) {
+                                char *for_command;
+
+                                if (!w[i] || !w[i]->target || !w[i]->session)
+                                        continue;
+
+                                if (!next_is_for)		/* XXX, get_uid(), get_nickname() */
+                                        for_command = format_string(params[2], get_nickname(w[i]->session, w[i]->target), get_uid(w[i]->session, w[i]->target));
+                                else
+                                        for_command = xstrdup(params[2]);
+                                command_exec(NULL, w[i]->session, for_command, 0);
+                                xfree(for_command);
+                        }
+			array_free(tmp);
+                        xfree(w);
+                }
+	} else {
+	        printq("invalid_params", name);
+		return -1;
+	}
+	return 0;
+}
+
+static COMMAND(cmd_help)
+{
+	list_t l;
+	if (params[0]) {
+		const char *p = (params[0][0] == '/' && xstrlen(params[0]) > 1) ? params[0] + 1 : params[0];
+		int plen;
+
+		if (!xstrcasecmp(p, ("set")) && params[1]) {
+			if (!quiet)
+				variable_help(params[1]);
+			return 0;
+		}
+
+						/* vvv - allow /help sess sth */
+                if (!xstrncasecmp(p, ("session"), xstrlen(p) > 3 ? xstrlen(p) : 3) && params[1]) {
+                        if (!quiet)
+                                session_help(session, params[1]);
+                        return 0;
+                }
+
+        	if (session && session->uid) {
+	                plen = (int)(xstrchr(session->uid, ':') - session->uid) + 1;
+		} else
+			plen = 0;
+	
+		for (l = commands; l; l = l->next) {
+			command_t *c = l->data;
+			
+			if (!xstrcasecmp(c->name, p) && (c->flags & COMMAND_ISALIAS)) {
+				printq("help_alias", p);
+				return -1;
+			}
+			if (!xstrcasecmp(c->name, p) && (c->flags & COMMAND_ISSCRIPT)) {
+				printq("help_script", p);
+				return -1;
+			}
+
+			if ((!xstrcasecmp(c->name, p) || !xstrcasecmp(c->name + plen, p)) && !(c->flags & COMMAND_ISALIAS) ) {
+				FILE *f; 
+				char *line, *params_help = NULL, *params_help_s, *brief = NULL, *tmp = NULL;
+				const char *seeking_name;
+				string_t s;
+				int found = 0;
+
+				if (c->plugin && c->plugin->name) {
+					char *tmp2;
+
+                                        if (!(f = help_path("commands", c->plugin->name))) {
+                                                print("help_command_file_not_found_plugin", c->plugin->name);
+						return -1;
+			                }
+					tmp2 = xstrchr(c->name, ':');
+					if (!tmp2)
+						seeking_name = c->name;
+					else
+				                seeking_name = tmp2 + 1;
+			        } else {
+					if (!(f = help_path("commands", NULL))) {
+		                	        print("help_command_file_not_found");
+						return -1;
+			                }
+
+	                		seeking_name = c->name;
+        			}
+			        while ((line = read_file(f, 0))) {
+			                if (!xstrcasecmp(line, seeking_name)) {
+			                        found = 1;
+			                        break;
+			                }
+			        }
+
+			        if (!found) {
+			                fclose(f);
+			                print("help_command_not_found", c->name);
+			                return -1;
+			        }
+
+			        line = read_file(f, 0);
+
+			        if ((tmp = xstrstr(line, (": "))))
+			                params_help = xstrdup(tmp + 2);
+			        else
+			                params_help = xstrdup((""));
+
+				params_help_s = strip_spaces(params_help);
+
+				line = read_file(f, 0);
+
+                                if ((tmp = xstrstr(line, (": "))))
+                                        brief = xstrdup(tmp + 2);
+                                else
+                                        brief = xstrdup(("?"));
+
+				tmp = NULL;
+
+			        if (xstrstr(brief, ("%")))
+			  		tmp = format_string(brief);
+
+	                        if (!xstrcmp(brief, (""))) {
+	                                xfree(brief);
+	                                brief = xstrdup(("?"));
+	                        }
+
+	                        if (xstrcmp(params_help_s, ("")))
+        	                        printq("help", (c->name) ? (c->name) : (""), params_help_s, tmp ? tmp : brief, "");
+	                        else
+	                                printq("help_no_params", (c->name) ? (c->name) : (""), tmp ? tmp : brief, (""));
+
+				xfree(brief);
+				xfree(params_help);
+				xfree(tmp);
+
+				s = string_init(NULL);
+			        while ((line = read_file(f, 0))) {
+			                if (line[0] != ('\t'))
+			                        break;
+					
+			                if (!xstrncmp(line, ("\t- "), 3) && xstrcmp(s->str, (""))) {
+			                        print("help_command_body", line);
+			                        string_clear(s);
+			                }
+					
+					if (!xstrncmp(line, ("\t"), 1) && xstrlen(line) == 1) {
+						string_append(s, "\n\r");
+						continue;
+					}
+					
+			                string_append(s, line + 1);
+
+			                if (line[xstrlen(line) - 1] != ' ')
+			                        string_append_c(s, ' ');
+			        }
+				
+				if (xstrcmp(s->str, (""))) {
+					char *tmp = format_string(s->str);
+                                        printq("help_command_body", tmp);
+					xfree(tmp);
+				}
+				fclose(f);
+			        string_free(s, 1);
+				return 0;
+			}
+		}
+	}
+
+	for (l = commands; l; l = l->next) {
+		command_t *c = l->data;
+
+		if (xisalnum(*c->name) && !(c->flags & COMMAND_ISALIAS)) {
+		    	char *blah = NULL;
+                        FILE *f;
+                        char *line, *params_help, *params_help_s, *brief, *tmp = NULL;
+                        const char *seeking_name;
+                        int found = 0;
+
+		        if (c->plugin && c->plugin->name) {
+				char *tmp2;
+
+	                        if (!(f = help_path("commands", c->plugin->name))) continue;
+
+				tmp2 = xstrchr(c->name, (':'));
+				if (!tmp2)
+					seeking_name = c->name;
+				else 
+	                                seeking_name = tmp2 + 1;
+                        } else {
+                                if (!(f = help_path("commands", NULL))) continue;
+
+                                seeking_name = c->name;
+                        }
+
+                        while ((line = read_file(f, 0))) {
+                        	if (!xstrcasecmp(line, seeking_name)) {
+                                	found = 1;
+                                        break;
+                                }
+                        }
+
+                        if (!found) {
+		                fclose(f);
+				continue;
+                        }
+
+			line = read_file(f, 0);
+		
+			if ((tmp = xstrstr(line, (": "))))
+                               params_help = xstrdup(tmp + 2);
+                        else
+                               params_help = xstrdup((""));
+
+			params_help_s = strip_spaces(params_help);	
+
+                        line = read_file(f, 0);
+
+                        if ((tmp = xstrstr(line, (": "))))
+ 	                       brief = xstrdup(tmp + 2);
+                        else
+                               brief = xstrdup(("?"));
+
+			if (xstrstr(brief, ("%")))
+			    	blah = format_string(brief);
+
+			if (!xstrcmp(brief, (""))) {
+				xfree(brief);
+				brief = xstrdup(("?"));
+			}
+
+			if (xstrcmp(params_help_s, ("")))
+				printq("help", c->name ? (c->name) : (""), params_help_s, blah ? blah : brief, (""));
+			else
+				printq("help_no_params", (c->name) ? (c->name) : (""), blah ? blah : brief, (""));
+			xfree(blah);
+			xfree(brief);
+			xfree(params_help);
+
+			fclose(f);
+		}
+	}
+
+	printq("help_footer");
+	printq("help_quick");
+	return 0;
+}
+
+static COMMAND(cmd_ignore)
+{
+	const char *uid;
+
+	if (*name == 'i' || *name == 'I') {
+		int flags, modified = 0;
+
+		if (!params[0]) {
+			list_t l;
+			int i = 0;
+			for (l = session->userlist; l; l = l->next) {
+				userlist_t *u = l->data;
+				int level;
+
+				if (!(level = ignored_check(session, u->uid)))
+					continue;
+
+				i = 1;
+
+				printq("ignored_list", format_user(session, u->uid), ignore_format(level));
+			}
+
+			if (!i)
+				printq("ignored_list_empty");
+
+			return 0;
+		}
+
+		if (params[0][0] == '#') {
+			return command_exec_format(NULL, NULL, quiet, ("/conference --ignore %s"), params[0]);
+		}
+
+		if (!(uid = get_uid(session, params[0]))) {
+			printq("user_not_found", params[0]);
+			return -1;
+		}
+
+                if ((flags = ignored_check(session, uid)))
+                        modified = 1;
+
+		if (params[1]) {
+			int __flags = ignore_flags(params[1]);
+
+			if (!__flags) {
+				printq("invalid_params", name);
+				return -1;
+			}
+
+                        flags |= __flags;
+		} else
+			flags = IGNORE_ALL;
+
+		if (modified)
+			ignored_remove(session, uid);
+
+                if (!ignored_add(session, uid, flags)) {
+                        if (modified)
+                                printq("ignored_modified", format_user(session, uid));
+                        else
+                                printq("ignored_added", format_user(session, uid));
+                        config_changed = 1;
+                }
+
+	} else {
+		int unignore_all = ((params[0] && !xstrcmp(params[0], "*")) ? 1 : 0);
+		int level;
+
+		if (!params[0]) {
+			printq("not_enough_params", name);
+			return -1;
+		}
+
+		if (params[0][0] == '#') {
+			return command_exec_format(NULL, NULL, quiet, ("/conference --unignore %s"), params[0]);
+		}
+		
+		if (!unignore_all && !(uid = get_uid(session, params[0]))) {
+			printq("user_not_found", params[0]);
+			return -1;
+		}
+
+		if (unignore_all) {
+			list_t l;
+			int x = 0;
+			
+			for (l = session->userlist; l; ) {
+				userlist_t *u = l->data;
+
+				l = l->next;
+
+				if (!ignored_remove(session, u->uid))
+					x = 1;
+
+				level = ignored_check(session, u->uid);
+			}
+
+			if (x) {
+				printq("ignored_deleted_all");
+				config_changed = 1;
+			} else {
+				printq("ignored_list_empty");
+				return -1;
+			}
+			
+			return 0;
+		}
+
+		level = ignored_check(session, uid);
+		
+		if (!ignored_remove(session, uid)) {
+			printq("ignored_deleted", format_user(session, params[0]));
+			config_changed = 1;
+		} else {
+			printq("error_not_ignored", format_user(session, params[0]));
+			return -1;
+		}
+	
+	}
+	return 0;
+}
+
+COMMAND(cmd_list)
+{
+	list_t l;
+	int count = 0, show_all = 1, show_away = 0, show_active = 0, show_inactive = 0, show_invisible = 0, show_descr = 0, show_blocked = 0, show_offline = 0, j;
+	char **argv = NULL, *show_group = NULL;
+	const char *tmp;
+	metacontact_t *m = NULL;
+	char *tparams0	= xstrdup(params[0]);		/* XXX, target */
+	char *params0;
+
+        if (!tparams0 && window_current->target) { 
+		tparams0 = xstrdup(window_current->target);
+	}
+	params0 = strip_quotes(tparams0);
+
+	if (params0 && (*params0 != '-' || userlist_find(session, params0))) {
+		char *status;
+		const char *group = params0;
+		userlist_t *u;
+		list_t res;
+		int invert = 0;
+		
+		/* list !@grupa */
+		if (group[0] == '!' && group[1] == '@') {
+			group++;
+			invert = 1;
+		}
+
+		/* list @grupa */
+		if (group[0] == '@' && xstrlen(group) > 1) {
+			string_t members = string_init(NULL);
+			char *__group;
+			int count = 0;
+			
+			for (l = session->userlist; l; l = l->next) {
+				u = l->data;
+
+				if (u->groups || invert) {
+					if ((!invert && ekg_group_member(u, group + 1)) || (invert && !ekg_group_member(u, group + 1))) {
+						if (count++)
+							string_append(members, ", ");
+						string_append(members, u->nickname);
+					}
+				}
+			}
+			
+			__group = saprintf("%s%s", ((invert) ? "!" : ""), group + 1);
+
+			if (count)
+				printq("group_members", __group, members->str);
+			else
+				printq("group_empty", __group);
+
+			xfree(__group);
+
+			string_free(members, 1);
+			
+			xfree(tparams0);
+			return 0;
+		}
+
+	        if (params0 && (tmp = xstrrchr(params0, '/'))) {
+        	        char *session_name = xstrndup(params0, xstrlen(params0) - xstrlen(tmp));
+	
+	                if (!session_find(session_name))
+	                        goto next;
+	
+	                tmp++;
+	                session = session_find(session_name);
+	        	if (!(u = userlist_find(session, tmp)) || !u->nickname) {
+	                        printq("user_not_found", tmp);
+				xfree(session_name);
+				xfree(tparams0);
+	                	return -1;
+			}
+	
+	                xfree(session_name);
+	                goto list_user;
+	        }
+
+next:
+		/* list _metacontact */
+		if (params0 && (m = metacontact_find(params0))) {
+        	        metacontact_item_t *i;
+	
+	                i = metacontact_find_prio(m);
+
+	                if (!i) {
+	                        printq("metacontact_item_list_empty");
+				xfree(tparams0);
+				return -1;
+	               	} 
+		
+			u = userlist_find_n(i->s_uid, i->name);
+
+	                status = format_string(format_find(ekg_status_label(u->status, u->descr, "metacontact_info_")), u->nickname, u->descr);
+
+	                printq("metacontact_info_header", params0);
+			printq("metacontact_info_status", status);
+	                printq("metacontact_info_footer", params0);
+
+			xfree(status);
+			xfree(tparams0);
+			return 0;
+		}
+	
+		if (!(u = userlist_find(session, params0)) || !u->nickname) {
+			printq("user_not_found", params0);
+			xfree(tparams0);
+			return -1;
+		}
+
+list_user:
+		status = format_string(format_find(ekg_status_label(u->status, u->descr, "user_info_")), 
+				u->nickname, u->descr);
+
+		printq("user_info_header", u->nickname, u->uid);
+		if (u->nickname && xstrcmp(u->nickname, u->nickname)) 
+			printq("user_info_nickname", u->nickname);
+
+		printq("user_info_status", status);
+                if (u->status_time && (u->status <= EKG_STATUS_NA)) {
+		        struct tm *status_time;
+			char buf[100];		
+
+			status_time = localtime(&(u->status_time));
+	        	if (!strftime(buf, sizeof(buf), format_find("user_info_status_time_format") ,status_time) && xstrlen(format_find("user_info_status_time_format"))>0)
+				xstrcpy(buf, "TOOLONG");
+
+
+			printq("user_info_status_time", buf);
+		}
+
+		if (u->last_status) {
+			char *last_status = format_string(format_find(ekg_status_label(u->last_status, u->last_descr, "user_info_")), 
+							u->nickname, u->last_descr);
+			printq("user_info_last_status", last_status);
+			xfree(last_status);
+		}
+
+		for (res = u->resources; res; res = res->next) {
+			ekg_resource_t *r = res->data;
+			char *resstatus; 
+
+			resstatus = format_string(format_find(ekg_status_label(r->status, r->descr, /* resource_info? senseless */ "user_info_")), 
+					/* here r->name ? */
+					 u->nickname, r->descr);
+			printq("resource_info_status", r->name, resstatus, itoa(r->prio));
+			xfree(resstatus);
+		}
+
+		if (ekg_group_member(u, "__blocked"))
+			printq("user_info_block", u->nickname);
+		if (ekg_group_member(u, "__offline"))
+			printq("user_info_offline", u->nickname);
+
+		query_emit_id(NULL, USERLIST_INFO, &u, &quiet);
+
+		if (u->groups) {
+			char *groups = group_to_string(u->groups, 0, 1);
+			printq("user_info_groups", groups);
+			xfree(groups);
+		}
+		if (u->status <= EKG_STATUS_NA) {
+			char buf[100];
+			struct tm *last_seen_time;
+			
+			if (u->last_seen) {
+				last_seen_time = localtime(&(u->last_seen));
+				if (!strftime(buf, sizeof(buf), format_find("user_info_last_seen_time"), last_seen_time) && xstrlen(format_find("user_info_last_seen_time"))>0)
+					xstrcpy(buf, "TOOLONG");
+				printq("user_info_last_seen", buf);
+			} else
+				printq("user_info_never_seen");
+		}
+			
+		printq("user_info_footer", u->nickname, u->uid);
+		
+		xfree(status);
+		xfree(tparams0);
+		return 0;
+	}
+	
+	/* list --active | --away | --inactive | --invisible | --description | --member | --blocked | --offline */
+	for (j = 0; params[j]; j++) {
+		int i;
+
+		argv = array_make(params[j], " \t", 0, 1, 1);
+
+	 	for (i = 0; argv[i]; i++) {
+			if (match_arg(argv[i], 'a', ("active"), 2)) {
+				show_all = 0;
+				show_active = 1;
+			}
+				
+			if (match_arg(argv[i], 'i', ("inactive"), 2) || match_arg(argv[i], 'n', ("notavail"), 2)) {
+				show_all = 0;
+				show_inactive = 1;
+			}
+			
+			if (match_arg(argv[i], 'A', ("away"), 2)) {
+				show_all = 0;
+				show_away = 1;
+			}
+			
+			if (match_arg(argv[i], 'I', ("invisible"), 2)) {
+				show_all = 0;
+				show_invisible = 1;
+			}
+
+			if (match_arg(argv[i], 'B', ("blocked"), 2)) {
+				show_all = 0;
+				show_blocked = 1;
+			}
+
+			if (match_arg(argv[i], 'o', ("offline"), 2)) {
+				show_all = 0;
+				show_offline = 1;
+			}
+
+			if (match_arg(argv[i], 'm', ("member"), 2)) {
+				if (j && argv[i+1]) {
+					int off = (argv[i+1][0] == '@' && xstrlen(argv[i+1]) > 1) ? 1 : 0;
+
+					show_group = xstrdup(argv[i+1] + off);
+				} else
+					if (params[i+1]) {
+						char **tmp = array_make(params[i+1], " \t", 0, 1, 1);
+						int off = (params[i+1][0] == '@' && xstrlen(params[i+1]) > 1) ? 1 : 0;
+
+ 						show_group = xstrdup(tmp[0] + off);
+						array_free(tmp);
+					}
+			}
+
+			if (match_arg(argv[i], 'd', ("description"), 2))
+				show_descr = 1;
+		}
+		array_free(argv);
+	}
+
+	{
+			/* ip/port currently can be fetched for GG only,
+			 * so this should remove unneeded slowdown for other sessions */
+		const int is_ipport_capable = !xstrncmp(session->uid, "gg:", 3);
+
+		for (l = session->userlist; l; l = l->next) {
+			userlist_t *u = l->data;
+			int show;
+
+			if (!u->nickname)
+				continue;
+
+			tmp = ekg_status_label(u->status, u->descr, "list_");
+
+			show = show_all;
+	#define SHOW_IF_S(x,y) if (show_##x && (u->status == EKG_STATUS_##y)) show = 1;
+			SHOW_IF_S(away, AWAY)
+			SHOW_IF_S(active, AVAIL)
+			SHOW_IF_S(inactive, NA)
+			SHOW_IF_S(invisible, INVISIBLE)
+			SHOW_IF_S(blocked, BLOCKED)
+	#undef SHOW_IF_S		
+			/* XXX nie chcialo mi sie zmiennej robic */
+			if (u->status == EKG_STATUS_ERROR)
+				show = 1;
+
+			if (show_descr && !u->descr)
+				show = 0;
+
+			if (show_group && !ekg_group_member(u, show_group))
+				show = 0;
+
+			if (show_offline && ekg_group_member(u, "__offline"))
+				show = 1;
+
+			if (show) {
+				const char *ip		= NULL;
+				const char *port	= NULL;
+				if (is_ipport_capable) {
+					int func		= EKG_USERLIST_PRIVHANDLER_GETVAR_IPPORT;
+					const char **__ip	= &ip;
+					const char **__port	= &port;
+					
+					query_emit_id(NULL, USERLIST_PRIVHANDLE, &u, &func, &__ip, &__port);
+				}
+
+				printq(tmp, format_user(session, u->uid), u->nickname, (ip ? ip : "0.0.0.0"), (port ? port : "0"), u->descr);
+				count++;
+			}
+		}
+	}
+
+	if (!count && !(show_descr || show_group) && show_all)
+		printq("list_empty");
+	xfree(show_group);
+	xfree(tparams0);
+	return 0;
+}
+
+static COMMAND(cmd_save) {
+	int ret = 0;
+	last_save = time(NULL);
+
+/* Changes 14 wrze 2006 (dj) */
+/* We try to save everything, but if smth not pass, try others */
+/* makes it executable even if we don't have sessions. */
+
+	/* set windows layout */
+	windows_save();
+
+	/* set default session */
+	if (config_sessions_save && session_current) {
+		xfree(config_session_default); config_session_default = xstrdup(session_current->uid);
+	}
+
+	if (session_write())		ret = -1;
+	if (config_write(params[0]))	ret = -1;
+	if (metacontact_write())	ret = -1;
+	if (script_variables_write())	ret = -1;
+
+	if (!ret) {
+		printq("saved");
+		config_changed = 0;
+		reason_changed = 0;
+	} else {
+		printq("error_saving");
+	}
+
+	return ret;
+}
+
+static COMMAND(cmd_set)
+{
+	const char *arg = NULL, *val = NULL;
+	int unset = 0, show_all = 0, res = 0;
+	char *value = NULL;
+	list_t l;
+
+	if (match_arg(params[0], 'a', ("all"), 1)) {
+		show_all = 1;
+		arg = params[1];
+		if (arg)
+			val = params[2];
+	} else {
+		arg = params[0];
+		if (arg)
+			val = params[1];
+	}
+	
+	if (arg && arg[0] == '-') {
+		unset = 1;
+		arg++;
+	}
+
+	if (arg && val) {
+		char **tmp = array_make(val, (""), 0, 0, 1);
+
+		value = xstrdup(tmp[0]);
+		array_free(tmp);
+	}
+
+	if ((!arg || !val) && !unset) {
+		int displayed = 0;
+
+		for (l = variables; l; l = l->next) {
+			variable_t *v = l->data;
+			
+			if ((!arg || !xstrcasecmp(arg, v->name)) && (v->display != 2 || xstrcmp(name, ("set")))) {
+				char *string = *(char**)(v->ptr);
+				int value = *(int*)(v->ptr);
+
+				if (!show_all && !arg && v->dyndisplay && !((v->dyndisplay)(v->name)))
+					continue;
+
+				if (!v->display) {
+					printq("variable", v->name, ("(...)"));
+					displayed = 1;
+					continue;
+				}
+
+				if (v->type == VAR_STR || v->type == VAR_FILE || v->type == VAR_DIR || v->type == VAR_THEME) {
+					char *tmp = (string) ? saprintf(("\"%s\""), string) : ("(none)");
+
+					printq("variable", v->name, tmp);
+					
+					if (string)
+						xfree(tmp);
+				}
+
+				if (v->type == VAR_BOOL)
+					printq("variable", v->name, (value) ? ("1 (on)") : ("0 (off)"));
+				
+				if ((v->type == VAR_INT || v->type == VAR_MAP) && !v->map)
+					printq("variable", v->name, itoa(value));
+
+				if (v->type == VAR_INT && v->map) {
+					char *tmp = NULL;
+					int i;
+
+					for (i = 0; v->map[i].label; i++)
+						if (v->map[i].value == value) {
+							tmp = saprintf(("%d (%s)"), value, v->map[i].label);
+							break;
+						}
+
+					if (!tmp)
+						tmp = saprintf(("%d"), value);
+
+					printq("variable", v->name, tmp);
+
+					xfree(tmp);
+				}
+
+				if (v->type == VAR_MAP && v->map) {
+					string_t s = string_init(itoa(value));
+					int i, first = 1;
+
+					for (i = 0; v->map[i].label; i++) {
+						if ((value & v->map[i].value) || (!value && !v->map[i].value)) {
+							string_append(s, (first) ? (" (") : (","));
+							first = 0;
+							string_append(s, v->map[i].label);
+						}
+					}
+
+					if (!first)
+						string_append_c(s, (')'));
+
+					printq("variable", v->name, s->str);
+
+					string_free(s, 1);
+				}
+
+				displayed = 1;
+			}
+		}
+
+		if (!displayed && params[0]) {
+			printq("variable_not_found", params[0]);
+			return -1;
+		}
+	} else {
+		variable_t *v = variable_find(arg);
+		theme_cache_reset();
+
+		if (!unset && !xstrcasecmp(value, ("t"))) {
+			if (v && v->type == VAR_BOOL) {
+				int t_value = *(int*)(v->ptr);
+			
+				xfree(value);
+				value = (t_value) ? xstrdup(("0")) : xstrdup(("1"));
+			}
+		} 
+
+		switch (variable_set(arg, (unset) ? NULL : value, 0)) {
+			case 0:
+			{
+				const char *my_params[2] = { (!unset) ? params[0] : params[0] + 1, NULL };
+
+				cmd_set(("set-show"), (const char **) my_params, NULL, NULL, quiet);
+				config_changed = 1;
+				last_save = time(NULL);
+				break;
+			}
+			case -1:
+				printq("variable_not_found", arg);
+				res = -1;
+				break;
+			case -2:
+				printq("variable_invalid", arg);
+				res = -1;
+				break;
+		}
+	}
+	
+	xfree(value);
+
+	return res;
+}
+
+static COMMAND(cmd_quit)
 {
     	char *reason;
 	list_t l;


Więcej informacji o liście dyskusyjnej ekg2-commit