847 lines · 19.9 KB · C
RawDownload
/* * ------------------------------------------------------- * Copyright (C) 2003-2007 Tommi Saviranta <wnd@iki.fi> * ------------------------------------------------------- * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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. */ #ifdef HAVE_CONFIG_H#include <config.h>#endif /* ifdef HAVE_CONFIG_H */ #include "parser.h"#include "common.h"#include "server.h"#include "miau.h"#include "perm.h"#include "error.h"#include "messages.h"#include "chanlog.h"#include "onconnect.h" #include <errno.h>#include <string.h>   static int	virgin = 1;	/* CFG_CHANNELS has effect only at start up. */ static int last_err_line;static int line;			/* Line we're processing. */static int listid = CFG_NOLIST;		/* List ID. */   /* Prototypes. */void assign_int(int *target, const char *data, const int min);void assign_boolean(int *target, const char *data);void assign_param(char **target, char *source);void parse_error(void);char *trim(char *data, const int mode);char *trimquotes(char *data);void assign_option(int *target, const char *, char *);int parse_option(const char *, char *);   /* * Writes "source" over "target". * * Old data if freed and new data is trimmed. */voidassign_param(char **target, char *source){	xfree(*target);	source = trim(source, SPACES);	if (source[0] == '\0') {		*target = NULL;	} else {		*target = xstrdup(source);	}} /* void assign_param(char **target, char *source) */   static voidassign_param_no_trim(char **target, char *source){	xfree(*target);	if (source[0] == '\0') {		*target = NULL;	} else {		*target = xstrdup(source);	}} /* static void assign_param_no_trim(char **target, char *source) */   /* * Add server to server-list. */voidadd_server(const char *name, int port, const char *pass, int timeout){	server_type	*server;	llist_node	*node; 	/* Must have a name for this server. */	if (name == NULL) { return; }	/* If port was not defined, use default. */	if (port == 0) { port = DEFAULT_PORT; } 	/*	 * We don't check if user has duplicate servers. If he does, he	 * probably has a reason for that.	 */ 	server = (server_type *) xmalloc(sizeof(server_type));	server->name = xstrdup(name);	server->port = port;	server->password = (char *) ((pass == NULL) ? NULL : xstrdup(pass));	server->timeout = (timeout > 0) ? timeout : 0;	server->working = 1;	node = llist_create(server);	llist_add_tail(node, &servers.servers);	servers.amount++;} /* void add_server(const char *name, int port, const char *pass,		int timeout) */   /* * Remove quotes around *data. * * Return pointer to trimmed string or NULL if there are no quotes. */char *trimquotes(char *data){	int l;	l = strlen(data) - 1;	if (data[0] != '"' || data[l] != '"') {		parse_error();		/* Bad quoting. */		return NULL;	}	data[l] = '\0';	return data + 1;} /* char *trimquotes(char *data) */   /* * Remove useless characters like whitespaces and comments. * * Return pointer to trimmed string. */char *trim(char *data, const int mode){	int	inside = 0;	char	*ptr; 	/* Skip whitespaces (minus linefeeds, they cannot exist). */	while (*data == ' ' || *data == '\t') { data++; } 	if (mode == LINE) {		/* Remove comments. */ 		ptr = data;		while (*ptr != '\0') {			if (*ptr == '"') {				inside ^= 1;			} else if (*ptr == '#' && ! inside) {				*ptr = '\0';				break;			}			ptr++;		}	} 	ptr = data + strlen(data) - 1;	/* Remove trailing whitespaces. */	while (ptr >= data && (*ptr == ' ' || *ptr == '\t')) {		*ptr = '\0';		ptr--;	} 	return data;} /* char *trim(char *data, const int mode) */   /* * Get an integer out of data. Set it over target. */voidassign_int(int *target, const char *data, const int min){	int n = min; /* Default to min. */ 	if (data != NULL) {		n = strtol(data, (char **) NULL, 10);		if (errno == ERANGE) {			parse_error();			return;		} 		if (n < min) { n = min; }	} 	*target = n;} /* void assign_int(int *target, const char *data, const int min) */   /* * Parse boolean value out of data. * * "true", "yes", "on", and "1" gives 1, * "false, "no", off", and "0" gives 0, * everything else prints an error. */voidassign_boolean(int *target, const char *data){	if (parse_option(data, "true\0yes\0on\0""1\0\0") != -1) {		*target = 1;	} else if (parse_option(data, "false\0no\0off\0""0\0\0") != -1) {		*target = 0;	} else {		parse_error();	}} /* void assign_boolean(int *target, const char *data) */   /* * Assign option. See parse_option(...). * * This prints error if val was not found. */voidassign_option(int *target, const char *val, char *options){	int t = parse_option(val, options);	if (t == -1) {		parse_error();	} else {		*target = t;	}} /* void assign_option(int *target, const char *val, char *options) */   /* * Parse option. * * Find "val" in "options", which is null-separated, (double) null-terminated * list of possible options. Index of word in "options" will define returned * value. * * Returns -1 if "val" is not found. */intparse_option(const char *val, char *options){	int i = 0;	/* Bad input means error in config. */	if (val == NULL || val[0] == '\0') {		return -1;	}	while (*options != '\0') {		if (xstrcmp(val, options) == 0) {			return i;		}		options = strchr(options, (int) '\0') + 1;		i++;	}	return -1;} /* int parse_option(const char *val, char *options) */   /* * Parse parameter definition that was already extracted from configuration * file. */voidparse_param(char *data){	char	*t = strchr(data, '=');	char	*val;	if (t == NULL) {		parse_error();	/* Didn't get mandatory '='-character. */		return;	}	*t = '\0'; 	data = trim(data, SPACES);	if (strchr(data, ' ') != NULL || strchr(data, '\t') != NULL) {		parse_error();		return;	} 	val = trim(t + 1, SPACES);	if (*val == '{') {		/* Not expecting any other data. */		if (val[1] != '\0') { parse_error(); } 		/* Resolve list-id. */		if (xstrcmp(data, "nicknames") == 0) {		/* nicknames */			listid = CFG_NICKNAMES;		} else if (xstrcmp(data, "servers") == 0) {	/* servers */			listid = CFG_SERVERS;		} else if (xstrcmp(data, "connhosts") == 0) {	/* connhosts */			listid = CFG_CONNHOSTS;		} else if (xstrcmp(data, "ignore") == 0) {	/* ignore */			listid = CFG_IGNORE;#ifdef AUTOMODE		} else if (xstrcmp(data, "automodes") == 0) {	/* automode */			listid = CFG_AUTOMODELIST;#endif /* ifdef AUTOMODE */#ifdef CHANLOG		} else if (xstrcmp(data, "chanlog") == 0) {	/* chanlog */			listid = CFG_CHANLOG;#endif /* ifdef CHANLOG */		} else if (xstrcmp(data, "channels") == 0) {	/* channels */			listid = CFG_CHANNELS;#ifdef ONCONNECT		} else if (xstrcmp(data, "onconnect") == 0) {	/* onconnect */			listid = CFG_ONCONNECT;#endif /* ifdef ONCONNECT */		} else {			listid = CFG_INVALID;			parse_error();		}		return;	}	val = trimquotes(val);	if (val == NULL) {		parse_error();		return;	} 	if (xstrcmp(data, "realname") == 0) {		/* realname */		assign_param(&cfg.realname, val);	} else if (xstrcmp(data, "username") == 0) {	/* username */		assign_param(&cfg.username, val);#ifdef NEED_CMDPASSWD	} else if (xstrcmp(data, "cmdpasswd") == 0) {	/* cmdpasswd */		assign_param(&cfg.cmdpasswd, val);#endif /* ifdef NEED_CMDPASSWD */#ifdef QUICKLOG	} else if (xstrcmp(data, "qloglength") == 0) {	/* qloglength */		assign_int(&cfg.qloglength, val, 0);#ifdef QLOGSTAMP	} else if (xstrcmp(data, "timestamp") == 0) {	/* timestamp */		/* See qlog.h for options' order. */		/* Double-terminate just to be sure. */		assign_option(&cfg.timestamp, val,				"none\0beginning\0end\0\0");#endif /* ifdef QLOGSTAMP */	} else if (xstrcmp(data, "flushqlog") == 0) {	/* flushqlog */		assign_boolean(&cfg.flushqlog, val);	} else if (xstrcmp(data, "autoqlog") == 0) {	/* autoqlog */		assign_int(&cfg.autoqlog, val, -1);#endif /* ifdef QUICKLOG */#ifdef NEED_LOGGING	} else if (xstrcmp(data, "logsuffix") == 0 ||	/* logsuffix */			xstrcmp(data, "logpostfix") == 0) { /* TODO remove me */		assign_param(&cfg.logsuffix, val);#endif /* ifdef NEED_LOGGING */#ifdef INBOX	} else if (xstrcmp(data, "inbox") == 0) {	/* inbox */		assign_boolean(&cfg.inbox, val);#endif /* ifdef INBOX */	} else if (xstrcmp(data, "listenport") == 0) {	/* listenport */		assign_int(&cfg.listenport, val, 0);	} else if (xstrcmp(data, "listenhost") == 0) {	/* listenhost */		assign_param(&cfg.listenhost, val);	} else if (xstrcmp(data, "password") == 0) {	/* password */		assign_param(&cfg.password, val);	} else if (xstrcmp(data, "leave") == 0) {	/* leave */		assign_boolean(&cfg.leave, val);	} else if (xstrcmp(data, "chandiscon") == 0) {	/* chandiscon */		/*		 * 0 = nothing		 * 1 = notice		 * 2 = part		 * 3 = privmsg		 */		assign_option(&cfg.chandiscon, val,				"nothing\0notice\0part\0privmsg\0\0");	} else if (xstrcmp(data, "leavemsg") == 0) {	/* leavemsg */		assign_param(&cfg.leavemsg, val);	} else if (xstrcmp(data, "awaymsg") == 0) {	/* awaymsg */		assign_param(&cfg.awaymsg, val);	} else if (xstrcmp(data, "usequitmsg") == 0) {	/* usequitmsg */		assign_boolean(&cfg.usequitmsg, val);	} else if (xstrcmp(data, "autoaway") == 0) {	/* autoaway */		/*		 * 0 = never		 * 1 = client detach		 * 2 = no clients attached		 */		assign_option(&cfg.autoaway, val,				"never\0detach\0noclients\0\0");	} else if (xstrcmp(data, "getnick") == 0) {	/* getnick */		/*		 * 0 = never		 * 1 = detached		 * 2 = attached		 * 3 = always		 *		 * Values are hardcoded all over miau.c.		 * This should be fixed even though code is quite clear.		 */		/* Double-terminate just to be sure. */		assign_option(&cfg.getnick, val,				"never\0detached\0attached\0always\0\0");	} else if (xstrcmp(data, "getnickinterval") == 0) {/* getnickinterval */		assign_int(&cfg.getnickinterval, val, 0);	} else if (xstrcmp(data, "bind") == 0) {	/* bind */		assign_param(&cfg.bind, val);#ifdef AUTOMODE	} else if (xstrcmp(data, "automodedelay") == 0) { /* automodedelay */		assign_int(&cfg.automodedelay, val, 0);#endif /* ifdef AUTOMODE */	} else if (xstrcmp(data, "antiidle") == 0) {	/* antiide */		assign_int(&cfg.antiidle, val, 0);	} else if (xstrcmp(data, "nevergiveup") == 0) {	/* nevergiveup */		assign_boolean(&cfg.nevergiveup, val);	} else if (xstrcmp(data, "norestricted") == 0) { /* norestricted */		assign_boolean(&cfg.jumprestricted, val);	} else if (xstrcmp(data, "stonedtimeout") == 0) { /* stonedtimeout*/		assign_int(&cfg.stonedtimeout, val, MINSTONEDTIMEOUT);	} else if (xstrcmp(data, "connecttimeout") == 0) { /* connecttimeout */		assign_int(&cfg.connecttimeout, val, MINCONNECTTIMEOUT);	} else if (xstrcmp(data, "reconnectdelay") == 0) { /* reconnectdelay */		assign_int(&cfg.reconnectdelay, val, MINRECONNECTDELAY);	} else if (xstrcmp(data, "rejoin") == 0) {	/* rejoin */		assign_boolean(&cfg.rejoin, val);	} else if (xstrcmp(data, "forwardmsg") == 0) {	/* forwardmsg */		assign_param(&cfg.forwardmsg, val);	} else if (xstrcmp(data, "forwardtime") == 0) {	/* forwardtime */		assign_int(&cfg.forwardtime, val, 30);	} else if (xstrcmp(data, "maxclients") == 0) {	/* maxclients */		assign_int(&cfg.maxclients, val, 1);#ifdef PRIVLOG	} else if (xstrcmp(data, "privlog") == 0) {	/* privlog */		/* See log.h for options' order. */		/* Double-terminate just to be sure. */		assign_option(&cfg.privlog, val,				"never\0detached\0attached\0always\0\0");#endif /* ifdef PRIVLOG */#ifdef DCCBOUNCE	} else if (xstrcmp(data, "dccbounce") == 0) {	/* dccbounce */		assign_boolean(&cfg.dccbounce, val);	} else if (xstrcmp(data, "dccbindhost") == 0) {		assign_param(&cfg.dccbindhost, val);#endif /* ifdef DCCBOUNCE */	} else if (xstrcmp(data, "nickfillchar") == 0) { /* nickfillchar */		cfg.nickfillchar = val[0];	} else if (xstrcmp(data, "usermode") == 0) {	/* usermode */		assign_param(&cfg.usermode, val);	} else if (xstrcmp(data, "maxnicklen") == 0) {	/* maxnicklen */		assign_int(&cfg.maxnicklen, val, 3);	} else if (xstrcmp(data, "floodtimer") == 0) {	/* floodtimer */		assign_int(&cfg.floodtimer, val, 0);	} else if (xstrcmp(data, "burstsize") == 0) {	/* burstsize */		assign_int(&cfg.burstsize, val, 1);	} else if (xstrcmp(data, "jointries") == 0) {	/* jointries */		assign_int(&cfg.jointries, val, 0);	} else if (xstrcmp(data, "statelog") == 0) {	/* statelog */		assign_boolean(&cfg.statelog, val);	} else if (xstrcmp(data, "noidentifycapab") == 0) {		assign_boolean(&cfg.no_identify_capab, val);	} else if (xstrcmp(data, "qlog_no_my_quit") == 0) {		assign_boolean(&cfg.qlog_no_my_quit, val);	} else if (xstrcmp(data, "privmsg_format") == 0) {		if (val != NULL && strstr(val, "%s") != NULL) {			assign_param_no_trim(&cfg.privmsg_fmt, val);		} else {			parse_error();		}	} else if (xstrcmp(data, "newserv_disconn") == 0) {		/* keep in sync with enum in miau.h! */		assign_option(&cfg.newserv_disconn, val,				"never\0newserver\0always\0\0");	} else {		parse_error();	}} /* void parse_param(char *data) */   /* * Parse list-item. */voidparse_list_line(char *data){	permlist_type	*permlist = NULL;	char		**param;	int		paramcount = 0;	int		n;	int		eol = 0;	int		ok = 0; 	int		inside = 0;		/* Inside quotes. */	char		*ptr;	char		*par;

Lines 1–500 of 847.