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 }