unrealircd

- supernets unrealircd source & configuration
git clone git://git.acid.vegas/unrealircd.git
Log | Files | Refs | Archive | README | LICENSE

api-isupport.c (8816B)

      1 /************************************************************************
      2  *   UnrealIRCd - Unreal Internet Relay Chat Daemon - src/api-isupport.c
      3  *   (c) 2004 Dominick Meglio and the UnrealIRCd Team
      4  *
      5  *   See file AUTHORS in IRC package for additional names of
      6  *   the programmers.
      7  *
      8  *   This program is free software; you can redistribute it and/or modify
      9  *   it under the terms of the GNU General Public License as published by
     10  *   the Free Software Foundation; either version 1, or (at your option)
     11  *   any later version.
     12  *
     13  *   This program is distributed in the hope that it will be useful,
     14  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     16  *   GNU General Public License for more details.
     17  *
     18  *   You should have received a copy of the GNU General Public License
     19  *   along with this program; if not, write to the Free Software
     20  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     21  */
     22 
     23 #include "unrealircd.h"
     24 
     25 ISupport *ISupports; /* List of ISUPPORT (005) tokens */
     26 #define MAXISUPPORTLINES 10
     27 
     28 MODVAR char *ISupportStrings[MAXISUPPORTLINES+1];
     29 
     30 void isupport_add_sorted(ISupport *is);
     31 void make_isupportstrings(void);
     32 
     33 /** Easier way to set a 005 name or name=value.
     34  * @param name   Name of the 005 token
     35  * @param value  Value of the 005 token (or NULL)
     36  * @note  The 'name' 005 token will be overwritten if it already exists.
     37  *        The 'value' may be NULL, in which case if there was a value
     38  *        it will be unset.
     39  */
     40 void ISupportSet(Module *module, const char *name, const char *value)
     41 {
     42 	ISupport *is = ISupportFind(name);
     43 	if (!is)
     44 		is = ISupportAdd(module, name, value);
     45 	ISupportSetValue(is, value);
     46 }
     47 
     48 /** Easy way to set a 005 name=value with printf style formatting.
     49  * @param name     Name of the 005 token
     50  * @param pattern  Value pattern for the 005 token (or NULL)
     51  * @param ...      Any variables needed for 'pattern'.
     52  * @note  The 'name' 005 token will be overwritten if it already exists.
     53  *        The 'pattern' may be NULL, in which case if there was a value
     54  *        it will be unset.
     55  */
     56 void ISupportSetFmt(Module *module, const char *name, const char *pattern, ...)
     57 {
     58 	const char *value = NULL;
     59 	char buf[256];
     60 	va_list vl;
     61 
     62 	if (pattern)
     63 	{
     64 		va_start(vl, pattern);
     65 		ircvsnprintf(buf, sizeof(buf), pattern, vl);
     66 		va_end(vl);
     67 		value = buf;
     68 	}
     69 	ISupportSet(module, name, value);
     70 }
     71 
     72 void ISupportDelByName(const char *name)
     73 {
     74 	ISupport *is = ISupportFind(name);
     75 	if (is)
     76 		ISupportDel(is);
     77 }
     78 
     79 extern void set_isupport_extban(void);
     80 extern void set_isupport_targmax(void);
     81 
     82 /**
     83  * Initializes the builtin isupport tokens.
     84  */
     85 void isupport_init(void)
     86 {
     87 	ISupportSet(NULL, "INVEX", NULL);
     88 	ISupportSet(NULL, "EXCEPTS", NULL);
     89 	ISupportSet(NULL, "ELIST", "MNUCT");
     90 	ISupportSet(NULL, "CASEMAPPING", "ascii");
     91 	ISupportSet(NULL, "NETWORK", NETWORK_NAME_005);
     92 	ISupportSetFmt(NULL, "CHANMODES",
     93 	               CHPAR1 "%s,%s,%s,%s",
     94 	               EXPAR1, EXPAR2, EXPAR3, EXPAR4);
     95 	ISupportSet(NULL, "CHANTYPES", "#");
     96 	ISupportSetFmt(NULL, "MODES", "%d", MAXMODEPARAMS);
     97 	ISupportSetFmt(NULL, "SILENCE", "%d", SILENCE_LIMIT);
     98 	if (WATCH_AWAY_NOTIFICATION)
     99 		ISupportSet(NULL, "WATCHOPTS", "A");
    100 	else
    101 		ISupportDelByName("WATCHOPTS");
    102 	ISupportSetFmt(NULL, "WATCH", "%d", MAXWATCH);
    103 	ISupportSet(NULL, "WALLCHOPS", NULL);
    104 	ISupportSetFmt(NULL, "AWAYLEN", "%d", iConf.away_length);
    105 	ISupportSetFmt(NULL, "KICKLEN", "%d", iConf.kick_length);
    106 	ISupportSetFmt(NULL, "TOPICLEN", "%d", iConf.topic_length);
    107 	ISupportSetFmt(NULL, "QUITLEN", "%d", iConf.quit_length);
    108 	ISupportSetFmt(NULL, "CHANNELLEN", "%d", CHANNELLEN);
    109 	ISupportSetFmt(NULL, "MINNICKLEN", "%d", iConf.min_nick_length);
    110 	ISupportSetFmt(NULL, "NICKLEN", "%d", iConf.nick_length);
    111 	ISupportSetFmt(NULL, "MAXNICKLEN", "%d", NICKLEN);
    112 	ISupportSetFmt(NULL, "MAXLIST", "b:%d,e:%d,I:%d", MAXBANS, MAXBANS, MAXBANS);
    113 	ISupportSetFmt(NULL, "CHANLIMIT", "#:%d", MAXCHANNELSPERUSER);
    114 	ISupportSetFmt(NULL, "MAXCHANNELS", "%d", MAXCHANNELSPERUSER);
    115 	ISupportSet(NULL, "SAFELIST", NULL);
    116 	ISupportSet(NULL, "NAMESX", NULL);
    117 	if (UHNAMES_ENABLED)
    118 		ISupportSet(NULL, "UHNAMES", NULL);
    119 	else
    120 		ISupportDelByName("UHNAMES");
    121 	ISupportSet(NULL, "DEAF", "d");
    122 	set_isupport_extban(); /* EXTBAN=xyz */
    123 	set_isupport_targmax(); /* TARGMAX=... */
    124 }
    125 
    126 /**
    127  * Sets or changes the value of an existing isupport token.
    128  *
    129  * @param isupport The pointer to the isupport handle.
    130  * @param value    The new value of the token (NULL indicates no value).
    131  */
    132 void ISupportSetValue(ISupport *isupport, const char *value)
    133 {
    134 	safe_strdup(isupport->value, value);
    135 	make_isupportstrings();
    136 }
    137 
    138 /**
    139  * Returns an isupport handle based on the given token name.
    140  *
    141  * @param token The isupport token to search for.
    142  * @return Returns the handle to the isupport token if it was found,
    143  *         otherwise NULL is returned.
    144  */
    145 ISupport *ISupportFind(const char *token)
    146 {
    147 	ISupport *isupport;
    148 
    149 	for (isupport = ISupports; isupport; isupport = isupport->next)
    150 	{
    151 		if (!strcasecmp(token, isupport->token))
    152 			return isupport;
    153 	}
    154 	return NULL;
    155 }
    156 
    157 /**
    158  * Adds a new isupport token.
    159  *
    160  * @param module The module which owns this token.
    161  * @param token  The name of the token to create.
    162  * @param value  The value of the token (NULL indicates no value).
    163  * @return Returns the handle to the new token if successful, otherwise NULL.
    164  *         The module's error code contains specific information about the
    165  *         error.
    166  */
    167 ISupport *ISupportAdd(Module *module, const char *token, const char *value)
    168 {
    169 	ISupport *isupport;
    170 	const char *c;
    171 
    172 	if (ISupportFind(token))
    173 	{
    174 		if (module)
    175 			module->errorcode = MODERR_EXISTS;
    176 		return NULL;
    177 	}
    178 	/* draft-brocklesby-irc-isupport:
    179 	 * token = a-zA-Z0-9 and 20 or less characters
    180 	 * value = ASCII 0x21 - 0x7E
    181 	 */
    182 	for (c = token; c && *c; c++)
    183 	{
    184 		if (!isalnum(*c))
    185 		{
    186 			if (module)
    187 				module->errorcode = MODERR_INVALID;
    188 			return NULL;
    189 		}
    190 	}
    191 	if (!token || !*token || c-token > 20)
    192 	{
    193 		if (module)
    194 			module->errorcode = MODERR_INVALID;
    195 		return NULL;
    196 	}
    197 	for (c = value; c && *c; c++)
    198 	{
    199 		if (*c < '!' || *c > '~')
    200 		{
    201 			if (module)
    202 				module->errorcode = MODERR_INVALID;
    203 			return NULL;
    204 		}
    205 	}
    206 
    207 	isupport = safe_alloc(sizeof(ISupport));
    208 	isupport->owner = module;
    209 	safe_strdup(isupport->token, token);
    210 	if (value)
    211 		safe_strdup(isupport->value, value);
    212 	isupport_add_sorted(isupport);
    213 	make_isupportstrings();
    214 	if (module)
    215 	{
    216 		ModuleObject *isupportobj = safe_alloc(sizeof(ModuleObject));
    217 		isupportobj->object.isupport = isupport;
    218 		isupportobj->type = MOBJ_ISUPPORT;
    219 		AddListItem(isupportobj, module->objects);
    220 		module->errorcode = MODERR_NOERROR;
    221 	}
    222 	return isupport;
    223 }
    224 
    225 /**
    226  * Removes the specified isupport token.
    227  *
    228  * @param isupport The token to remove.
    229  */
    230 void ISupportDel(ISupport *isupport)
    231 {
    232 	DelListItem(isupport, ISupports);
    233 	if (isupport->owner)
    234 	{
    235 		ModuleObject *mo;
    236 		for (mo = isupport->owner->objects; mo; mo = mo->next)
    237 		{
    238 			if (mo->type == MOBJ_ISUPPORT && mo->object.isupport == isupport)
    239 			{
    240 				DelListItem(mo, isupport->owner->objects);
    241 				safe_free(mo);
    242 				break;
    243 			}
    244 		}
    245 	}
    246 	safe_free(isupport->token);
    247 	safe_free(isupport->value);
    248 	safe_free(isupport);
    249 	make_isupportstrings();
    250 }
    251 
    252 /**
    253  * Builds isupport token strings.
    254  * Respects both the 13 token limit and the 512 buffer limit.
    255  */
    256 void make_isupportstrings(void)
    257 {
    258 	int i;
    259 #define ISUPPORTLEN BUFSIZE-HOSTLEN-NICKLEN-39
    260 	int bufsize = ISUPPORTLEN;
    261 	int tokcnt = 0;
    262 	ISupport *isupport;
    263 	char tmp[ISUPPORTLEN];
    264 
    265 	/* Free any previous strings */
    266 	for (i = 0; ISupportStrings[i]; i++)
    267 		safe_free(ISupportStrings[i]);
    268 
    269 	i = 0;
    270 	ISupportStrings[i] = safe_alloc(bufsize+1);
    271 
    272 	for (isupport = ISupports; isupport; isupport = isupport->next)
    273 	{
    274 		if (isupport->value)
    275 			snprintf(tmp, sizeof(tmp), "%s=%s", isupport->token, isupport->value);
    276 		else
    277 			strlcpy(tmp, isupport->token, sizeof(tmp));
    278 
    279 		tokcnt++;
    280 		if ((strlen(ISupportStrings[i]) + strlen(tmp) + 1 >= ISUPPORTLEN) || (tokcnt == 13))
    281 		{
    282 			/* No room or max tokens reached: start a new buffer */
    283 			ISupportStrings[++i] = safe_alloc(bufsize+1);
    284 			tokcnt = 1;
    285 			if (i == MAXISUPPORTLINES)
    286 				abort(); /* should never happen anyway */
    287 		}
    288 
    289 		if (*ISupportStrings[i])
    290 			strlcat(ISupportStrings[i], " ", ISUPPORTLEN);
    291 		strlcat(ISupportStrings[i], tmp, ISUPPORTLEN);
    292 	}
    293 }
    294 
    295 void isupport_add_sorted(ISupport *n)
    296 {
    297 	ISupport *e;
    298 
    299 	if (!ISupports)
    300 	{
    301 		ISupports = n;
    302 		return;
    303 	}
    304 
    305 	for (e = ISupports; e; e = e->next)
    306 	{
    307 		if (strcmp(n->token, e->token) < 0)
    308 		{
    309 			/* Insert us before */
    310 			if (e->prev)
    311 				e->prev->next = n;
    312 			else
    313 				ISupports = n; /* new head */
    314 			n->prev = e->prev;
    315 
    316 			n->next = e;
    317 			e->prev = n;
    318 			return;
    319 		}
    320 		if (!e->next)
    321 		{
    322 			/* Append us at end */
    323 			e->next = n;
    324 			n->prev = e;
    325 			return;
    326 		}
    327 	}
    328 }