| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217 |
- /*
- * Copyright (C) 1997 Robey Pointer
- * Copyright (C) 1999 - 2002 Eggheads Development Team
- * Copyright (C) 2002 - 2014 Bryan Drewery
- *
- * 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.
- *
- * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
- /*
- * tclchan.c -- part of channels.mod
- *
- */
- static int FindElement(char *resultBuf, const char *list, size_t listLength,
- const char **elementPtr, const char **nextPtr,
- size_t *sizePtr, int *bracePtr)
- {
- const char *p = list;
- const char *elemStart = NULL; /* Points to first byte of first element. */
- const char *limit = (list + listLength); /* Points just after list's last byte. */
- int openBraces = 0; /* Brace nesting level during parse. */
- int inQuotes = 0;
- size_t size = 0; /* lint. */
- const char *p2 = NULL;
- /*
- * Skim off leading white space and check for an opening brace or
- * quote. We treat embedded NULLs in the list as bytes belonging to
- * a list element.
- */
- while ((p < limit) && egg_isspace(*p)) { /* INTL: ISO space. */
- p++;
- }
- if (p == limit) { /* no element found */
- elemStart = limit;
- goto done;
- }
- if (*p == '{') {
- openBraces = 1;
- p++;
- } else if (*p == '"') {
- inQuotes = 1;
- p++;
- }
- elemStart = p;
- if (bracePtr != 0) {
- *bracePtr = openBraces;
- }
- /*
- * Find element's end (a space, close brace, or the end of the string).
- */
- while (p < limit) {
- switch (*p) {
- /*
- * Open brace: don't treat specially unless the element is in
- * braces. In this case, keep a nesting count.
- */
- case '{':
- if (openBraces != 0) {
- openBraces++;
- }
- break;
- /*
- * Close brace: if element is in braces, keep nesting count and
- * quit when the last close brace is seen.
- */
- case '}':
- if (openBraces > 1) {
- openBraces--;
- } else if (openBraces == 1) {
- size = (p - elemStart);
- p++;
- if ((p >= limit) || egg_isspace(*p)) { /* INTL: ISO space. */
- goto done;
- }
- /*
- * Garbage after the closing brace; return an error.
- */
- if (resultBuf) {
- p2 = p;
- while ((p2 < limit)
- && (!egg_isspace(*p2)) /* INTL: ISO space. */
- && (p2 < p+20)) {
- p2++;
- }
- // snprintf(resultBuf, RESULT_LEN, "list element in braces followed by \"%.*s\" instead of space", (int) (p2-p), p);
- }
- return ERROR;
- }
- break;
- /*
- * Backslash: skip over everything up to the end of the
- * backslash sequence.
- */
- /* case '\\': {
- Tcl_UtfBackslash(p, &numChars, NULL);
- p += (numChars - 1);
- break;
- }
- */
- /*
- * Space: ignore if element is in braces or quotes; otherwise
- * terminate element.
- */
- case ' ':
- case '\f':
- case '\n':
- case '\r':
- case '\t':
- case '\v':
- if ((openBraces == 0) && !inQuotes) {
- size = (p - elemStart);
- goto done;
- }
- break;
- /*
- * Double-quote: if element is in quotes then terminate it.
- */
- case '"':
- if (inQuotes) {
- size = (p - elemStart);
- p++;
- if ((p >= limit) || egg_isspace(*p)) { /* INTL: ISO space */
- goto done;
- }
- /*
- * Garbage after the closing quote; return an error.
- */
- if (resultBuf) {
- p2 = p;
- while ((p2 < limit)
- && (!egg_isspace(*p2)) /* INTL: ISO space */
- && (p2 < p+20)) {
- p2++;
- }
- // sprintf(resultBuf, "list element in quotes followed by \"%.*s\" %s", (int) (p2-p), p, "instead of space");
- }
- return ERROR;
- }
- break;
- }
- p++;
- }
- /*
- * End of list: terminate element.
- */
- if (p == limit) {
- if (openBraces != 0) {
- if (resultBuf) {
- simple_snprintf(resultBuf, RESULT_LEN, "unmatched open brace in list");
- }
- return ERROR;
- } else if (inQuotes) {
- if (resultBuf) {
- simple_snprintf(resultBuf, RESULT_LEN, "unmatched open quote in list");
- }
- return ERROR;
- }
- size = (p - elemStart);
- }
- done:
- while ((p < limit) && (egg_isspace(*p))) { /* INTL: ISO space. */
- p++;
- }
- *elementPtr = elemStart;
- *nextPtr = p;
- if (sizePtr != 0) {
- *sizePtr = size;
- }
- return OK;
- }
- /* unneeded?
- int CopyAndCollapse(int count, const char *src, char *dst)
- {
- register char c;
- int numRead;
- int newCount = 0;
- int backslashCount;
- for (c = *src; count > 0; src++, c = *src, count--) {
- if (c == '\\') {
- backslashCount = Tcl_UtfBackslash(src, &numRead, dst);
- dst += backslashCount;
- newCount += backslashCount;
- src += numRead-1;
- count -= numRead-1;
- } else {
- *dst = c;
- dst++;
- newCount++;
- }
- }
- *dst = 0;
- return newCount;
- }
- */
- int SplitList(char *resultBuf, const char *list, int *argcPtr, const char ***argvPtr)
- {
- const char **argv = NULL;
- const char *l = NULL;
- const char *element = NULL;
- char *p = NULL;
- int result, brace = 0;
- size_t size = 2; /* initialized to 1 for NULL pointer */
- size_t length, elSize, i = 0;
- /*
- * Figure out how much space to allocate. There must be enough
- * space for both the array of pointers and also for a copy of
- * the list. To estimate the number of pointers needed, count
- * the number of space characters in the list.
- */
- for (l = list; *l != 0; l++) {
- if (egg_isspace(*l)) { /* INTL: ISO space. */
- size++;
- }
- }
- argv = (const char **) my_calloc(1, (unsigned) ((size * sizeof(char *)) + (l - list) + 1 + 15)); /* 15 cuz the tcl src is hard to follow */
- length = strlen(list);
- for (p = ((char *) argv) + size*sizeof(char *); *list != 0; i++) {
- const char *prevList = list;
- result = FindElement(resultBuf, list, length, &element, &list, &elSize, &brace);
- length -= (list - prevList);
- if (result != OK) {
- free((char *) argv);
- return result;
- }
- if (*element == 0) {
- break;
- }
- if (i >= size) {
- free((char *) argv);
- if (resultBuf)
- strlcpy(resultBuf, "internal error in SplitList", RESULT_LEN);
- return ERROR;
- }
- argv[i] = p;
- if (brace) {
- memcpy(p, element, elSize);
- p += elSize;
- *p = 0;
- p++;
- } else {
- /* CopyAndCollapse(elSize, element, p); */
- memcpy(p, element, elSize);
- p += elSize + 1;
- }
- }
- argv[i] = NULL;
- *argvPtr = argv;
- *argcPtr = i;
- return OK;
- }
- /* Parse options for a channel.
- */
- int channel_modify(char *result, struct chanset_t *chan, int items, char **item, bool cmd)
- {
- bool error = 0, changed_groups = false;
- int old_status = chan->status,
- old_mode_mns_prot = chan->mode_mns_prot,
- old_mode_pls_prot = chan->mode_pls_prot;
- char s[121] = "", result_extra[RESULT_LEN / 2] = "";
- if (result)
- result[0] = 0;
- for (register int i = 0; i < items; i++) {
- /* Chanchar template
- } else if (!strcmp(item[i], "temp")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel temp needs argument", RESULT_LEN);
- return ERROR;
- }
- strlcpy(chan->temp, item[i], sizeof(chan->temp));
- check_temp(chan);
- */
- if (!strcmp(item[i], "chanmode")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel chanmode needs argument", RESULT_LEN);
- return ERROR;
- }
- strlcpy(s, item[i], sizeof(s));
- set_mode_protect(chan, s);
- } else if (!strcmp(item[i], "groups")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel groups needs argument", RESULT_LEN);
- return ERROR;
- }
- // Get string into right format
- bd::String changroups(item[i]);
- // Replace commas with spaces to be in proper format
- changroups = changroups.sub(",", " ");
- changroups.trim();
- *(chan->groups) = changroups.split(" ");
- changed_groups = true;
- } else if (!strcmp(item[i], "topic")) {
- char *p = NULL;
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "topic needs argument", RESULT_LEN);
- return ERROR;
- }
- p = replace(item[i], "{", "[");
- p = replace(p, "}", "]");
- strlcpy(chan->topic, p, sizeof(chan->topic));
- } else if (!cmd && !strcmp(item[i], "addedby")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "addedby needs argument", RESULT_LEN);
- return ERROR;
- }
- strlcpy(chan->added_by, item[i], sizeof(chan->added_by));
- } else if (!cmd && !strcmp(item[i], "addedts")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "addedts needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->added_ts = atoi(item[i]);
- } else if (!strcmp(item[i], "limit")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel limit needs argument", RESULT_LEN);
- return ERROR;
- }
- if (chan->limitraise && !atoi(item[i]) && dolimit(chan)) //limitraise was disabled by the user
- add_mode(chan, '-', 'l', "");
- chan->limitraise = atoi(item[i]);
- chan->limit_prot = 0;
- } else if (!strcmp(item[i], "fish-key")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel fish-key needs argument", RESULT_LEN);
- return ERROR;
- }
- bd::String key(item[i]);
- key.trim();
- set_fish_key(chan->dname, key);
- strlcpy(chan->fish_key, key.c_str(), sizeof(chan->fish_key));
- } else if (!strcmp(item[i], "ban-time")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel ban-time needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->ban_time = atoi(item[i]);
- } else if (!strcmp(item[i], "exempt-time")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel exempt-time needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->exempt_time = atoi(item[i]);
- } else if (!strcmp(item[i], "invite-time")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel invite-time needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->invite_time = atoi(item[i]);
- } else if (!strcmp(item[i], "capslimit") || !strcmp(item[i], "caps-limit")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel caps-limit needs argument", RESULT_LEN);
- return ERROR;
- }
- int capslimit = atoi(item[i]);
- if (capslimit > 100 || capslimit < 0 || item[i][0] == '-') {
- if (result)
- strlcpy(result, "channel caps-limit out of range (0-100)", RESULT_LEN);
- return ERROR;
- }
- chan->capslimit = capslimit;
- } else if (!strcmp(item[i], "colorlimit") || !strcmp(item[i], "color-limit")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel color-limit needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->colorlimit = atoi(item[i]);
- } else if (!strcmp(item[i], "closed-ban")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel closed-ban needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->closed_ban = atoi(item[i]);
- } else if (!strcmp(item[i], "voice-moderate")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel voice-moderate needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->voice_moderate = atoi(item[i]);
- if (chan->mode_mns_prot & CHANMODER && chan->voice_moderate)
- chan->voice_moderate = 0;
- } else if (!strcmp(item[i], "closed-invite")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel closed-invite needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->closed_invite = atoi(item[i]);
- if (chan->mode_mns_prot & CHANINV && chan->closed_invite)
- chan->closed_invite = 0;
- } else if (!strcmp(item[i], "closed-private")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel closed-private needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->closed_private = atoi(item[i]);
- if (chan->mode_mns_prot & CHANPRIV && chan->closed_private)
- chan->closed_private = 0;
- } else if (!strcmp(item[i], "voice-non-ident")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel voice-ident needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->voice_non_ident = atoi(item[i]);
- } else if (!strcmp(item[i], "bad-cookie")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel bad-cookie needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->bad_cookie = deflag_translate(item[i]);
- } else if (!strcmp(item[i], "manop")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel manop needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->manop = deflag_translate(item[i]);
- } else if (!strcmp(item[i], "mdop")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel mdop needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->mdop = deflag_translate(item[i]);
- } else if (!strcmp(item[i], "mop")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel mop needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->mop = deflag_translate(item[i]);
- } else if (!strcmp(item[i], "revenge")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel revenge needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->revenge = deflag_translate(item[i]);
- } else if (!strcmp(item[i], "knock")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel knock needs argument", RESULT_LEN);
- return ERROR;
- }
- if (!str_isdigit(item[i])) {
- if (!strcasecmp("Op", item[i]))
- chan->knock_flags = CHAN_FLAG_OP;
- else if (!strcasecmp("Voice", item[i]))
- chan->knock_flags = CHAN_FLAG_VOICE;
- else if (!strcasecmp("User", item[i]))
- chan->knock_flags = CHAN_FLAG_USER;
- else if (!strcasecmp("None", item[i]))
- chan->knock_flags = 0;
- else {
- if (result)
- strlcpy(result, "channel knock only accepts Op|Voice|User|None", RESULT_LEN);
- return ERROR;
- }
- } else
- chan->knock_flags = atoi(item[i]);
- } else if (!strcmp(item[i], "flood-exempt")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel flood-exempt needs argument", RESULT_LEN);
- return ERROR;
- }
- if (!str_isdigit(item[i])) {
- if (!strcasecmp("Op", item[i]))
- chan->flood_exempt_mode = CHAN_FLAG_OP;
- else if (!strcasecmp("Voice", item[i]))
- chan->flood_exempt_mode = CHAN_FLAG_VOICE;
- else if (!strcasecmp("None", item[i]))
- chan->flood_exempt_mode = 0;
- else {
- if (result)
- strlcpy(result, "channel flood-exempt only accepts Op|Voice|None", RESULT_LEN);
- return ERROR;
- }
- } else
- chan->flood_exempt_mode = atoi(item[i]);
- } else if (!strcmp(item[i], "closed-exempt")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel closed-exempt needs argument", RESULT_LEN);
- return ERROR;
- }
- if (!str_isdigit(item[i])) {
- if (!strcasecmp("Op", item[i]))
- chan->closed_exempt_mode = CHAN_FLAG_OP;
- else if (!strcasecmp("Voice", item[i]))
- chan->closed_exempt_mode = CHAN_FLAG_VOICE;
- else if (!strcasecmp("None", item[i]))
- chan->closed_exempt_mode = 0;
- else {
- if (result)
- strlcpy(result, "channel closed-exempt only accepts Op|Voice|None", RESULT_LEN);
- return ERROR;
- }
- } else
- chan->closed_exempt_mode = atoi(item[i]);
- } else if (!strcmp(item[i], "flood-lock-time")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel flood-lock-time needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->flood_lock_time = atoi(item[i]);
- } else if (!strcmp(item[i], "auto-delay")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel auto-delay needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->auto_delay = atoi(item[i]);
- } else if (!strcmp(item[i], "ban-type")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel ban-type needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->ban_type = atoi(item[i]);
- } else if (!strcmp(item[i], "protect-backup")) {
- i++;
- if (i >= items) {
- if (result)
- strlcpy(result, "channel protect-backup needs argument", RESULT_LEN);
- return ERROR;
- }
- chan->protect_backup = atoi(item[i]);
- }
- /* Chanint template
- * } else if (!strcmp(item[i], "temp")) {
- * i++;
- * if (i >= items) {
- * if (result)
- * strlcpy(result, "channel temp needs argument", RESULT_LEN);
- * return ERROR;
- * }
- * chan->temp = atoi(item[i]);
- */
- else if (!strcmp(item[i], "+floodban"))
- chan->status |= CHAN_FLOODBAN;
- else if (!strcmp(item[i], "-floodban"))
- chan->status &= ~CHAN_FLOODBAN;
- else if (!strcmp(item[i], "+enforcebans"))
- chan->status |= CHAN_ENFORCEBANS;
- else if (!strcmp(item[i], "-enforcebans"))
- chan->status &= ~CHAN_ENFORCEBANS;
- else if (!strcmp(item[i], "+dynamicbans"))
- chan->status |= CHAN_DYNAMICBANS;
- else if (!strcmp(item[i], "-dynamicbans"))
- chan->status &= ~CHAN_DYNAMICBANS;
- else if (!strcmp(item[i], "-userbans"))
- chan->status |= CHAN_NOUSERBANS;
- else if (!strcmp(item[i], "+userbans"))
- chan->status &= ~CHAN_NOUSERBANS;
- else if (!strcmp(item[i], "+bitch"))
- chan->status |= CHAN_BITCH;
- else if (!strcmp(item[i], "-bitch"))
- chan->status &= ~CHAN_BITCH;
- else if (!strcmp(item[i], "+nodesynch"))
- chan->status |= CHAN_NODESYNCH;
- else if (!strcmp(item[i], "-nodesynch"))
- chan->status &= ~CHAN_NODESYNCH;
- else if (!strcmp(item[i], "+inactive"))
- chan->status |= CHAN_INACTIVE;
- else if (!strcmp(item[i], "-inactive"))
- chan->status&= ~CHAN_INACTIVE;
- else if (!strcmp(item[i], "+secret"))
- chan->status |= CHAN_SECRET;
- else if (!strcmp(item[i], "-secret"))
- chan->status &= ~CHAN_SECRET;
- else if (!strcmp(item[i], "+cycle"))
- chan->status |= CHAN_CYCLE;
- else if (!strcmp(item[i], "-cycle"))
- chan->status &= ~CHAN_CYCLE;
- else if (!strcmp(item[i], "+dynamicexempts"))
- chan->status |= CHAN_DYNAMICEXEMPTS;
- else if (!strcmp(item[i], "-dynamicexempts"))
- chan->status &= ~CHAN_DYNAMICEXEMPTS;
- else if (!strcmp(item[i], "-userexempts"))
- chan->status |= CHAN_NOUSEREXEMPTS;
- else if (!strcmp(item[i], "+userexempts"))
- chan->status &= ~CHAN_NOUSEREXEMPTS;
- else if (!strcmp(item[i], "+dynamicinvites"))
- chan->status |= CHAN_DYNAMICINVITES;
- else if (!strcmp(item[i], "-dynamicinvites"))
- chan->status &= ~CHAN_DYNAMICINVITES;
- else if (!strcmp(item[i], "-userinvites"))
- chan->status |= CHAN_NOUSERINVITES;
- else if (!strcmp(item[i], "+userinvites"))
- chan->status &= ~CHAN_NOUSERINVITES;
- else if (!strcmp(item[i], "+closed"))
- chan->status |= CHAN_CLOSED;
- else if (!strcmp(item[i], "-closed"))
- chan->status &= ~CHAN_CLOSED;
- else if (HAVE_TAKE && !strcmp(item[i], "+take"))
- chan->status |= CHAN_TAKE;
- else if (HAVE_TAKE && !strcmp(item[i], "-take"))
- chan->status &= ~CHAN_TAKE;
- else if (!HAVE_TAKE && !strcmp(item[i], "+take"))
- chan->status |= CHAN_BITCH;
- else if (!HAVE_TAKE && !strcmp(item[i], "-take"))
- chan->status &= ~CHAN_BITCH;
- else if (!strcmp(item[i], "+voice"))
- chan->status |= CHAN_VOICE;
- else if (!strcmp(item[i], "-voice"))
- chan->status &= ~CHAN_VOICE;
- else if (!strcmp(item[i], "+autoop"))
- chan->status |= CHAN_AUTOOP;
- else if (!strcmp(item[i], "-autoop"))
- chan->status &= ~CHAN_AUTOOP;
- else if (!strcmp(item[i], "+botbitch"))
- chan->status |= CHAN_BOTBITCH;
- else if (!strcmp(item[i], "-botbitch"))
- chan->status &= ~CHAN_BOTBITCH;
- else if (!strcmp(item[i], "+rbl"))
- chan->status |= CHAN_RBL;
- else if (!strcmp(item[i], "-rbl"))
- chan->status &= ~CHAN_RBL;
- else if (!strcmp(item[i], "+voicebitch"))
- chan->status |= CHAN_VOICEBITCH;
- else if (!strcmp(item[i], "-voicebitch"))
- chan->status &= ~CHAN_VOICEBITCH;
- else if (!strcmp(item[i], "+protect"))
- chan->status |= CHAN_PROTECT;
- else if (!strcmp(item[i], "-protect"))
- chan->status &= ~CHAN_PROTECT;
- /* Chanflag template
- * else if (!strcmp(item[i], "+temp"))
- * chan->status |= CHAN_TEMP;
- * else if (!strcmp(item[i], "-temp"))
- * chan->status &= ~CHAN_TEMP;
- */
- else if (!strcmp(item[i], "+fastop"))
- chan->status |= CHAN_FASTOP;
- else if (!strcmp(item[i], "-fastop"))
- chan->status &= ~CHAN_FASTOP;
- else if (!strcmp(item[i], "+private"))
- chan->status |= CHAN_PRIVATE;
- else if (!strcmp(item[i], "-private"))
- chan->status &= ~CHAN_PRIVATE;
- else if (!strcmp(item[i], "+backup"))
- chan->status |= CHAN_BACKUP;
- else if (!strcmp(item[i], "-backup"))
- chan->status &= ~CHAN_BACKUP;
- /* ignore wasoptest, stopnethack and clearbans in chanfile, remove
- this later */
- else if (!cmd && !HAVE_TAKE && !strcmp(item[i], "+take")) ;
- else if (!cmd && !HAVE_TAKE && !strcmp(item[i], "-take")) ;
- else if (!cmd && !strcmp(item[i], "stopnethack-mode")) ;
- else if (!cmd && !strcmp(item[i], "revenge-mode")) ;
- else if (!cmd && !strcmp(item[i], "+meankicks")) ;
- else if (!cmd && !strcmp(item[i], "-meankicks")) ;
- else if (!cmd && !strcmp(item[i], "+nomassjoin")) ;
- else if (!cmd && !strcmp(item[i], "-nomassjoin")) ;
- else if (!cmd && !strcmp(item[i], "+revenge")) ;
- else if (!cmd && !strcmp(item[i], "-revenge")) ;
- else if (!cmd && !strcmp(item[i], "+revengebot")) ;
- else if (!cmd && !strcmp(item[i], "-revengebot")) ;
- else if (!cmd && !strcmp(item[i], "+manop")) ;
- else if (!cmd && !strcmp(item[i], "-manop")) ;
- else if (!cmd && !strcmp(item[i], "+dontkickops")) ;
- else if (!cmd && !strcmp(item[i], "-dontkickops")) ;
- else if (!cmd && !strcmp(item[i], "+nomdop")) ;
- else if (!cmd && !strcmp(item[i], "-nomdop")) ;
- else if (!cmd && !strcmp(item[i], "+protectfriends")) ;
- else if (!cmd && !strcmp(item[i], "-protectfriends")) ;
- else if (!cmd && !strcmp(item[i], "+protectops")) ;
- else if (!cmd && !strcmp(item[i], "-protectops")) ;
- else if (!cmd && !strcmp(item[i], "+punish")) ;
- else if (!cmd && !strcmp(item[i], "-punish")) ;
- else if (!cmd && !strcmp(item[i], "+seen")) ;
- else if (!cmd && !strcmp(item[i], "-seen")) ;
- else if (!cmd && !strcmp(item[i], "+secret")) ;
- else if (!cmd && !strcmp(item[i], "-secret")) ;
- else if (!cmd && !strcmp(item[i], "-stopnethack")) ;
- else if (!cmd && !strcmp(item[i], "+stopnethack")) ;
- else if (!cmd && !strcmp(item[i], "-wasoptest")) ;
- else if (!cmd && !strcmp(item[i], "+wasoptest")) ; /* Eule 01.2000 */
- else if (!cmd && !strcmp(item[i], "+clearbans")) ;
- else if (!cmd && !strcmp(item[i], "-clearbans")) ;
- else if (!cmd && !strncmp(item[i], "need-", 5)) ;
- else if (!strncmp(item[i], "flood-", 6)) {
- int *pthr = NULL;
- interval_t *ptime = NULL;
- char *p = NULL;
- if (!strcmp(item[i] + 6, "*")) {
- i++;
- if (i >= items) {
- if (result)
- simple_snprintf(result, RESULT_LEN, "%s needs argument", item[i - 1]);
- return ERROR;
- }
- p = strchr(item[i], ':');
- int thr = 0;
- interval_t time = 0;
- if (p) {
- *p++ = 0;
- thr = atoi(item[i]);
- time = atoi(p);
- *--p = ':';
- } else {
- thr = atoi(item[i]);
- time = 1;
- }
- chan->flood_pub_thr = thr;
- chan->flood_pub_time = time;
- chan->flood_mpub_thr = thr;
- chan->flood_mpub_time = time;
- chan->flood_bytes_thr = thr;
- chan->flood_bytes_time = time;
- chan->flood_mbytes_thr = thr;
- chan->flood_mbytes_time = time;
- chan->flood_join_thr = thr;
- chan->flood_join_time = time;
- chan->flood_ctcp_thr = thr;
- chan->flood_ctcp_time = time;
- chan->flood_mctcp_thr = thr;
- chan->flood_mctcp_time = time;
- chan->flood_kick_thr = thr;
- chan->flood_kick_time = time;
- chan->flood_deop_thr = thr;
- chan->flood_deop_time = time;
- chan->flood_nick_thr = thr;
- chan->flood_nick_time = time;
- chan->flood_mjoin_thr = thr;
- chan->flood_mjoin_time = time;
- } else if (!strcmp(item[i] + 6, "chan")) {
- pthr = &chan->flood_pub_thr;
- ptime = &chan->flood_pub_time;
- } else if (!strcmp(item[i] + 6, "bytes")) {
- pthr = &chan->flood_bytes_thr;
- ptime = &chan->flood_bytes_time;
- } else if (!strcmp(item[i] + 6, "join")) {
- pthr = &chan->flood_join_thr;
- ptime = &chan->flood_join_time;
- } else if (!strcmp(item[i] + 6, "ctcp")) {
- pthr = &chan->flood_ctcp_thr;
- ptime = &chan->flood_ctcp_time;
- } else if (!strcmp(item[i] + 6, "kick")) {
- pthr = &chan->flood_kick_thr;
- ptime = &chan->flood_kick_time;
- } else if (!strcmp(item[i] + 6, "deop")) {
- pthr = &chan->flood_deop_thr;
- ptime = &chan->flood_deop_time;
- } else if (!strcmp(item[i] + 6, "nick")) {
- pthr = &chan->flood_nick_thr;
- ptime = &chan->flood_nick_time;
- } else if (!strcmp(item[i] + 6, "mjoin")) {
- pthr = &chan->flood_mjoin_thr;
- ptime = &chan->flood_mjoin_time;
- } else if (!strcmp(item[i] + 6, "mpub")) {
- pthr = &chan->flood_mpub_thr;
- ptime = &chan->flood_mpub_time;
- } else if (!strcmp(item[i] + 6, "mbytes")) {
- pthr = &chan->flood_mbytes_thr;
- ptime = &chan->flood_mbytes_time;
- } else if (!strcmp(item[i] + 6, "mctcp")) {
- pthr = &chan->flood_mctcp_thr;
- ptime = &chan->flood_mctcp_time;
- } else { /* Ignore for optimal forward compatibility */
- i++;
- continue;
- }
- if (pthr && ptime) { //Ignore flood-*
- i++;
- if (i >= items) {
- if (result)
- simple_snprintf(result, RESULT_LEN, "%s needs argument", item[i - 1]);
- return ERROR;
- }
- p = strchr(item[i], ':');
- if (p) {
- *p++ = 0;
- *pthr = atoi(item[i]);
- *ptime = atoi(p);
- *--p = ':';
- } else {
- *pthr = atoi(item[i]);
- *ptime = 1;
- }
- }
- } else {
- if (result && item[i][0]) { /* ignore "" */
- if (!result[0])
- strlcpy(result, "illegal channel option: ", RESULT_LEN);
- if (result_extra[0])
- strlcat(result_extra, " ", sizeof(result_extra));
- strlcat(result_extra, item[i], sizeof(result_extra));
- }
- error = 1;
- }
- }
- if ((chan->status ^ old_status) & CHAN_TAKE)
- chan->status |= CHAN_BITCH; // to avoid bots still mass opping from +take from not using cookies
- if (!conf.bot->hub && (chan != chanset_default)) {
- // Check if groups changed or +/-backup set
- if (!restarting && !loading && (changed_groups || ((old_status ^ chan->status) & (CHAN_INACTIVE | CHAN_BACKUP)))) {
- check_shouldjoin(chan);
- }
- if (me_op(chan)) {
- if ((old_status ^ chan->status) & (CHAN_ENFORCEBANS|CHAN_NOUSERBANS|CHAN_DYNAMICBANS|CHAN_NOUSEREXEMPTS|CHAN_NOUSERINVITES|CHAN_DYNAMICEXEMPTS|CHAN_DYNAMICINVITES)) {
- recheck_channel(chan, 1);
- /* Does a change in channel flag affect client status in the channel? */
- } else if ((chan->status ^ old_status) & (CHAN_BITCH | CHAN_BOTBITCH | CHAN_PRIVATE | CHAN_CLOSED | CHAN_VOICE | CHAN_VOICEBITCH )) {
- recheck_channel(chan, 0);
- } else if ((old_status & CHAN_TAKE) && !(chan->status & CHAN_TAKE)) {
- //Set -take, fetch bans/exempts/invites
- recheck_channel(chan, 2);
- } else if (old_mode_pls_prot != chan->mode_pls_prot || old_mode_mns_prot != chan->mode_mns_prot) {
- recheck_channel_modes(chan);
- }
- }
- }
- if (result && result[0] && result_extra[0])
- strlcat(result, result_extra, RESULT_LEN);
- if (error)
- return ERROR;
- return OK;
- }
- static void init_masklist(masklist *m)
- {
- m->mask = (char *) my_calloc(1, 1);
- m->who = NULL;
- m->next = NULL;
- }
- /* Initialize out the channel record.
- */
- static void init_channel(struct chanset_t *chan, bool reset)
- {
- chan->channel.maxmembers = 0;
- chan->channel.mode = 0;
- chan->channel.members = 0;
- chan->channel.splitmembers = 0;
- if (!reset)
- my_setkey(chan, NULL);
- chan->channel.ban = (masklist *) my_calloc(1, sizeof(masklist));
- init_masklist(chan->channel.ban);
- chan->channel.exempt = (masklist *) my_calloc(1, sizeof(masklist));
- init_masklist(chan->channel.exempt);
- chan->channel.invite = (masklist *) my_calloc(1, sizeof(masklist));
- init_masklist(chan->channel.invite);
- chan->channel.member = (memberlist *) my_calloc(1, sizeof(memberlist));
- chan->channel.member->nick[0] = 0;
- chan->channel.member->next = NULL;
- chan->channel.topic = NULL;
- chan->channel.floodtime = new bd::HashTable<bd::String, bd::HashTable<flood_t, time_t> >;
- chan->channel.floodnum = new bd::HashTable<bd::String, bd::HashTable<flood_t, int> >;
- chan->channel.cached_members = new bd::HashTable<bd::String, memberlist*>;
- /* Don't clear out existing roles, keep them until rebalancing
- * to not create a window of missing roles. */
- if (!chan->bot_roles) {
- chan->bot_roles = new bd::HashTable<bd::String, int>;
- chan->role_bots = new bd::HashTable<short, bd::Array<bd::String> >;
- chan->role = 0;
- }
- chan->needs_role_rebalance = 1;
- }
- static void clear_masklist(masklist *m)
- {
- masklist *temp = NULL;
- for (; m; m = temp) {
- temp = m->next;
- if (m->mask)
- free(m->mask);
- if (m->who)
- free(m->who);
- free(m);
- }
- }
- /* Clear out channel data from memory.
- */
- void clear_channel(struct chanset_t *chan, bool reset)
- {
- memberlist *m = NULL, *m1 = NULL;
- if (chan->channel.topic)
- free(chan->channel.topic);
- for (m = chan->channel.member; m; m = m1) {
- m1 = m->next;
- delete_member(m);
- }
- clear_masklist(chan->channel.ban);
- chan->channel.ban = NULL;
- clear_masklist(chan->channel.exempt);
- chan->channel.exempt = NULL;
- clear_masklist(chan->channel.invite);
- chan->channel.invite = NULL;
- chan->channel.last_eI = 0;
- chan->ircnet_status = 0;
- // chan->ircnet_status &= ~CHAN_HAVEBANS;
- delete chan->channel.floodtime;
- chan->channel.floodtime = NULL;
- delete chan->channel.floodnum;
- chan->channel.floodnum = NULL;
- /* Don't clear out existing roles if resetting, keep them until rebalancing
- * to not create a window of missing roles. */
- if (!reset) {
- delete chan->bot_roles;
- chan->bot_roles = NULL;
- delete chan->role_bots;
- chan->role_bots = NULL;
- }
- if (chan->channel.cached_members) {
- if (chan->channel.cached_members->size()) {
- bd::Array<bd::String> member_uhosts(chan->channel.cached_members->keys());
- for (size_t i = 0; i < member_uhosts.length(); ++i) {
- const bd::String uhost(member_uhosts[i]);
- // Delete the cached member
- m = (*chan->channel.cached_members)[uhost];
- delete_member(m);
- // Remove the cached member (not technically needed as it is deleted below, but for completeness.)
- chan->channel.cached_members->remove(uhost);
- }
- }
- delete chan->channel.cached_members;
- chan->channel.cached_members = NULL;
- }
- if (reset)
- init_channel(chan, 1);
- for (size_t i = 0; i < MODES_PER_LINE_MAX; ++i) {
- if (chan->cmode[i].op) {
- free(chan->cmode[i].op);
- chan->cmode[i].op = NULL;
- }
- if (chan->ccmode[i].op) {
- free(chan->ccmode[i].op);
- chan->ccmode[i].op = NULL;
- }
- }
- }
- /* Create new channel and parse commands.
- */
- int channel_add(char *result, const char *newname, char *options, bool isdefault)
- {
- /* When loading userfile */
- if (newname && newname[0] && loading && !strcmp(newname, "default"))
- isdefault = 1;
- if (!newname || !newname[0] || (!isdefault && !strchr(CHANMETA, newname[0]))) {
- if (result)
- strlcpy(result, "invalid channel prefix", RESULT_LEN);
- return ERROR;
- }
- if (strchr(newname, ',') != NULL) {
- if (result)
- strlcpy(result, "invalid channel name", RESULT_LEN);
- return ERROR;
- }
- const char **item = NULL;
- int items = 0;
- char buf[3001] = "";
- simple_snprintf(buf, sizeof(buf), "chanmode { %s }", glob_chanmode);
- if (!isdefault) { // These are passed in in 'options'
- strlcat(buf, " ", sizeof(buf));
- strlcat(buf, def_chanset, sizeof(buf));
- }
- // Add in 'default' channel options
- if (!isdefault && chanset_default) {
- bd::String default_chan_options = channel_to_string(chanset_default);
- strlcat(buf, " ", sizeof(buf));
- strlcat(buf, default_chan_options.c_str(), sizeof(buf));
- }
- if (options && options[0]) {
- strlcat(buf, " ", sizeof(buf));
- strlcat(buf, options, sizeof(buf));
- }
- if (SplitList(result, buf, &items, &item) != OK)
- return ERROR;
- bool join = 0;
- struct chanset_t *chan = NULL;
- int ret = OK;
- if ((chan = findchan_by_dname(newname))) {
- /* Already existing channel, maybe a reload of the channel file */
- chan->status &= ~CHAN_FLAGGED; /* don't delete me! :) */
- } else {
- chan = (struct chanset_t *) my_calloc(1, sizeof(struct chanset_t));
- /* These are defaults, bzero already set them 0, but we set them for future reference */
- chan->limit_prot = 0;
- chan->limit = 0;
- chan->closed_ban = 0;
- chan->closed_private = 1;
- chan->closed_invite = 1;
- chan->voice_moderate = 1;
- chan->voice_non_ident = 1;
- chan->auto_delay = 5;
- chan->ban_type = 3;
- chan->revenge = DEFLAG_REACT;
- /* Chanint template
- * chan->temp = 0;
- */
- chan->groups = new bd::Array<bd::String>;
- *(chan->groups) << "main";
- chan->protect_backup = 1;
- chan->fish_key[0] = 0;
- chan->knock_flags = 0;
- chan->flood_lock_time = 120;
- chan->flood_exempt_mode = 0;
- chan->flood_pub_thr = 0;
- chan->flood_pub_time = 0;
- chan->flood_bytes_thr = 0;
- chan->flood_bytes_time = 0;
- chan->flood_ctcp_thr = 5;
- chan->flood_ctcp_time = 30;
- chan->flood_join_thr = 0;
- chan->flood_join_time = 0;
- chan->flood_deop_thr = 8;
- chan->flood_deop_time = 10;
- chan->flood_kick_thr = 0;
- chan->flood_kick_time = 0;
- chan->flood_nick_thr = 0;
- chan->flood_nick_time = 0;
- chan->flood_mjoin_thr = 6;
- chan->flood_mjoin_time = 1;
- chan->capslimit = 0;
- chan->colorlimit = 0;
- chan->flood_mpub_thr = 20;
- chan->flood_mpub_time = 1;
- chan->flood_mbytes_thr = 1000;
- chan->flood_mbytes_time = 1;
- chan->flood_mctcp_thr = 7;
- chan->flood_mctcp_time = 1;
- chan->limitraise = 20;
- chan->ban_time = global_ban_time;
- chan->exempt_time = global_exempt_time;
- chan->invite_time = global_invite_time;
- chan->channel.jointime = 0;
- chan->channel.parttime = 0;
- chan->channel.fighting = 0;
- chan->channel.drone_set_mode = 0;
- chan->channel.drone_jointime = 0;
- chan->channel.drone_joins = 0;
- chan->channel.last_eI = 0;
- chan->channel.floodtime = NULL;
- chan->channel.floodnum = NULL;
- /* We _only_ put the dname (display name) in here so as not to confuse
- * any code later on. chan->name gets updated with the channel name as
- * the server knows it, when we join the channel. <cybah>
- */
- strlcpy(chan->dname, newname, sizeof(chan->dname));
- /* Initialize chan->channel info */
- if (isdefault) {
- if (chanset_default)
- remove_channel(chanset_default);
- chanset_default = chan;
- } else {
- init_channel(chan, 0);
- list_append((struct list_type **) &chanset, (struct list_type *) chan);
- /* Channel name is stored in xtra field for sharebot stuff */
- if (!conf.bot->hub && !isdefault)
- join = 1;
- }
- }
- /* If loading is set, we're loading the userfile. Ignore errors while
- * reading userfile and just return OK. This is for compatability
- * if a user goes back to an eggdrop that no-longer supports certain
- * (channel) options.
- */
- if ((channel_modify(result, chan, items, (char **) item, 0) != OK)) {
- putlog(LOG_ERROR, "*", "Error parsing channel options for %s: %s", chan->dname, result);
- if (!loading)
- ret = ERROR;
- }
-
- free(item);
- if (join && shouldjoin(chan))
- join_chan(chan);
- return ret;
- }
- /* vim: set sts=2 sw=2 ts=8 et: */
|