From: pk910 Date: Tue, 14 Feb 2012 21:15:28 +0000 (+0100) Subject: added AdvTopic (advanced topic) with multiple delimiters X-Git-Url: http://git.pk910.de/?p=srvx.git;a=commitdiff_plain;h=1bf0d430020a45aa7dc3b098234eb9df2c5ba294 added AdvTopic (advanced topic) with multiple delimiters --- diff --git a/src/chanserv.c b/src/chanserv.c index 5ca8a01..d50c914 100644 --- a/src/chanserv.c +++ b/src/chanserv.c @@ -113,6 +113,7 @@ #define KEY_MAX_TIME "max_time" #define KEY_NOTES "notes" #define KEY_TOPIC_MASK "topic_mask" +#define KEY_ADVTOPIC_ENTRIES "adv_topic" #define KEY_OWNER_TRANSFER "owner_transfer" #define KEY_EXPIRE "expire" @@ -262,6 +263,7 @@ static const struct message_entry msgtab[] = { { "CSMSG_TOPIC_LOCKED", "The %s topic is locked." }, { "CSMSG_MASK_BUT_NO_TOPIC", "Warning: $b%s$b does not have a default topic, but you just set the topic mask." }, { "CSMSG_TOPIC_MISMATCH", "Warning: The default topic for $b%s$b does not match the topic mask; changing it anyway." }, + { "CSMSG_ADVTOPIC_INVALID_ID", "%d is an invalid advtopic id." }, { "CSMSG_MODES_SET", "Channel modes are now $b%s$b." }, { "CSMSG_DEFAULTED_MODES", "Channel modes for $b%s$b are set to their defaults." }, @@ -279,6 +281,7 @@ static const struct message_entry msgtab[] = { { "CSMSG_INVALID_NUMERIC", "$b%d$b is not a valid choice. Choose one:" }, { "CSMSG_SET_DEFAULT_TOPIC", "$bDefaultTopic$b %s" }, { "CSMSG_SET_TOPICMASK", "$bTopicMask $b %s" }, + { "CSMSG_SET_ADVTOPIC", "$bAdvTopic $b %s" }, { "CSMSG_SET_GREETING", "$bGreeting $b %s" }, { "CSMSG_SET_USERGREETING", "$bUserGreeting$b %s" }, { "CSMSG_SET_MODES", "$bModes $b %s" }, @@ -1229,6 +1232,7 @@ register_channel(struct chanNode *cNode, char *registrar) struct chanData *channel; enum levelOption lvlOpt; enum charOption chOpt; + int i; channel = calloc(1, sizeof(struct chanData)); @@ -1245,6 +1249,8 @@ register_channel(struct chanNode *cNode, char *registrar) channel->lvlOpts[lvlOpt] = levelOptions[lvlOpt].default_value; for(chOpt = 0; chOpt < NUM_CHAR_OPTIONS; ++chOpt) channel->chOpts[chOpt] = charOptions[chOpt].default_value; + for(i = 0; i < MAXADVTOPICENTRIES; i++) + channel->advtopic[i] = NULL; channel->prev = NULL; channel->next = channelList; @@ -1436,6 +1442,7 @@ unregister_channel(struct chanData *channel, const char *reason) { struct mod_chanmode change; char msgbuf[MAXLEN]; + int i; /* After channel unregistration, the following must be cleaned up: @@ -1471,6 +1478,11 @@ unregister_channel(struct chanData *channel, const char *reason) free(channel->greeting); free(channel->user_greeting); free(channel->topic_mask); + + for(i = 0; i < MAXADVTOPICENTRIES; i++) { + if(channel->advtopic[i]) + free(channel->advtopic[i]); + } if(channel->prev) channel->prev->next = channel->next; @@ -4323,8 +4335,34 @@ bad_topic(struct chanNode *channel, struct userNode *user, const char *new_topic struct chanData *cData = channel->channel_info; if(check_user_level(channel, user, lvlEnfTopic, 1, 0)) return 0; - if(cData->topic_mask) - return !match_ircglob(new_topic, cData->topic_mask); + if(cData->topic_mask) + { + if(cData->flags & CHANNEL_ADVTOPIC) + { + //this implementation is a little bit dirty but i haven't found a better, faster solution, yet... + char topicmask[TOPICLEN]; + int skipnum, topicpos = 0; + char *ptr = cData->topic_mask; + for(;*ptr;ptr++) { //replace all the %[0-9]* variables with * + switch(*ptr) { + case '%': + for(skipnum = 0; isdigit(ptr[1]) && skipnum < 3; ptr++, skipnum++) {} //skip up to 3 numbers + if(skipnum) + topicmask[topicpos++] = '*'; + else + topicmask[topicpos++] = *ptr; + break; + default: + topicmask[topicpos++] = *ptr; + break; + } + } + topicmask[topicpos] = 0; + return !match_ircglob(new_topic, topicmask); + } + else + return !match_ircglob(new_topic, cData->topic_mask); + } else if(cData->topic) return irccasecmp(new_topic, cData->topic); else @@ -4362,30 +4400,96 @@ static CHANSERV_FUNC(cmd_topic) char new_topic[TOPICLEN+1], tchar; int pos=0, starpos=-1, dpos=0, len; - while((tchar = topic_mask[pos++]) && (dpos <= TOPICLEN)) + if(cData->flags & CHANNEL_ADVTOPIC) { - switch(tchar) + //first check if there is a leading 'modifier id' + int advtopic_index = 0; + char numbuf[4]; + int numpos; + for(; topic[pos]; pos++) { - case '*': - if(starpos != -1) - goto bad_mask; - len = strlen(topic); - if((dpos + len) > TOPICLEN) - len = TOPICLEN + 1 - dpos; - memcpy(new_topic+dpos, topic, len); - dpos += len; - starpos = pos; - break; - case '\\': tchar = topic_mask[pos++]; /* and fall through */ - default: new_topic[dpos++] = tchar; break; + if(topic[pos] == ' ') + { + //leading number found, cut off and store value in advtopic_index + topic[pos] = 0; + advtopic_index = atoi(topic) - 1; //no zerobase + topic = &topic[pos+1]; + /* If they say "!topic 2 *", unset advtopic id 2. */ + if((topic[0] == '*') && (topic[1] == 0)) + topic[0] = 0; + } + if(!isdigit(topic[pos])) + break; + } + if(advtopic_index < 0 || advtopic_index > MAXADVTOPICENTRIES) + { + //invalid id! + reply("CSMSG_ADVTOPIC_INVALID_ID", advtopic_index); + return 0; + } + if(cData->advtopic[advtopic_index]) + free(cData->advtopic[advtopic_index]); + cData->advtopic[advtopic_index] = (topic[0] ? strdup(topic) : NULL); + char *ptr = topic_mask; + while(*ptr && (dpos <= TOPICLEN)) + { + switch(*ptr) + { + case '%': + ptr++; + for(numpos = 0; isdigit(*ptr) && numpos < 3; ptr++) { + numbuf[numpos++] = *ptr; + } + numbuf[numpos] = 0; + if(!numpos || (advtopic_index = atoi(numbuf)) <= 0 || advtopic_index > MAXADVTOPICENTRIES) { + ptr -= numpos+1; + new_topic[dpos++] = *ptr; //is % again + break; + } + ptr--; + advtopic_index--; //no zero base + if(!cData->advtopic[advtopic_index]) + break; //just leave it empty + len = strlen(cData->advtopic[advtopic_index]); + if((dpos + len) > TOPICLEN) + len = TOPICLEN + 1 - dpos; + memcpy(new_topic+dpos, cData->advtopic[advtopic_index], len); + dpos += len; + break; + case '\\': + ptr++; /* and fall through */ + default: + new_topic[dpos++] = *ptr; + break; + } + ptr++; + } + } else { + while((tchar = topic_mask[pos++]) && (dpos <= TOPICLEN)) + { + switch(tchar) + { + case '*': + if(starpos != -1) + goto bad_mask; + len = strlen(topic); + if((dpos + len) > TOPICLEN) + len = TOPICLEN + 1 - dpos; + memcpy(new_topic+dpos, topic, len); + dpos += len; + starpos = pos; + break; + case '\\': tchar = topic_mask[pos++]; /* and fall through */ + default: new_topic[dpos++] = tchar; break; + } + } + if((dpos > TOPICLEN) || tchar) + { + bad_mask: + reply("CSMSG_TOPICMASK_CONFLICT1", channel->name, topic_mask); + reply("CSMSG_TOPICMASK_CONFLICT2", TOPICLEN); + return 0; } - } - if((dpos > TOPICLEN) || tchar) - { - bad_mask: - reply("CSMSG_TOPICMASK_CONFLICT1", channel->name, topic_mask); - reply("CSMSG_TOPICMASK_CONFLICT2", TOPICLEN); - return 0; } new_topic[dpos] = 0; SetChannelTopic(channel, chanserv, new_topic, 1); @@ -5799,6 +5903,11 @@ static MODCMD_FUNC(chan_opt_dynlimit) CHANNEL_BINARY_OPTION("CSMSG_SET_DYNLIMIT", CHANNEL_DYNAMIC_LIMIT); } +static MODCMD_FUNC(chan_opt_advtopic) +{ + CHANNEL_BINARY_OPTION("CSMSG_SET_ADVTOPIC", CHANNEL_ADVTOPIC); +} + static MODCMD_FUNC(chan_opt_offchannel) { struct chanData *cData = channel->channel_info; @@ -8227,6 +8336,16 @@ chanserv_channel_read(const char *key, struct record_data *hir) } } + obj = database_get_data(channel, KEY_ADVTOPIC_ENTRIES, RECDB_OBJECT); + for(it = dict_first(obj); it; it = iter_next(it)) + { + struct record_data *rd = iter_data(it); + if(rd->type != RECDB_QSTRING) continue; + int advtopic_index = atoi(iter_key(it)); + if(advtopic_index < 0 || advtopic_index >= MAXADVTOPICENTRIES) continue; + cData->advtopic[advtopic_index] = (rd ? strdup(rd->d.qstring) : NULL); + } + if(!IsSuspended(cData) && (str = database_get_data(channel, KEY_MODES, RECDB_QSTRING)) && (argc = split_line(str, 0, ArrayLength(argv), argv)) @@ -8499,6 +8618,16 @@ chanserv_write_channel(struct saxdb_context *ctx, struct chanData *channel) high_present = chanserv_write_users(ctx, channel->users); chanserv_write_bans(ctx, channel->bans); + if(channel->flags & CHANNEL_ADVTOPIC) { + saxdb_start_record(ctx, KEY_ADVTOPIC_ENTRIES, 0); + int advtopic_index; + for(advtopic_index = 0; advtopic_index < MAXADVTOPICENTRIES; advtopic_index++) { + if(channel->advtopic[advtopic_index]) + saxdb_write_string(ctx, strtab(advtopic_index), channel->advtopic[advtopic_index]); + } + saxdb_end_record(ctx); + } + if(dict_size(channel->notes)) { dict_iterator_t it; @@ -8804,6 +8933,7 @@ init_chanserv(const char *nick) DEFINE_CHANNEL_OPTION(ctcpusers); DEFINE_CHANNEL_OPTION(ctcpreaction); DEFINE_CHANNEL_OPTION(inviteme); + DEFINE_CHANNEL_OPTION(advtopic); DEFINE_CHANNEL_OPTION(unreviewed); modcmd_register(chanserv_module, "set expire", chan_opt_expire, 1, 0, "flags", "+helping", NULL); modcmd_register(chanserv_module, "set unreviewed on", NULL, 0, 0, "flags", "+helping", NULL); diff --git a/src/chanserv.h b/src/chanserv.h index ac2dfdb..2aba69c 100644 --- a/src/chanserv.h +++ b/src/chanserv.h @@ -67,6 +67,7 @@ enum charOption { #define CHANNEL_PEON_INVITE 0x00000080 /* (1 << 7) - DEPRECATED */ #define CHANNEL_OFFCHANNEL 0x00000100 /* (1 << 8) */ #define CHANNEL_UNREVIEWED 0x00000200 /* (1 << 9) */ +#define CHANNEL_ADVTOPIC 0x00000400 /* (1 << 10) */ /* Flags with values over 0x20000000 or (1 << 29) will not work * because chanData.flags is a 30-bit field. */ @@ -75,6 +76,8 @@ enum charOption { #define IsSuspended(x) ((x)->flags & CHANNEL_SUSPENDED) #define IsOffChannel(x) (((x)->flags & CHANNEL_OFFCHANNEL) && (off_channel > 1)) +#define MAXADVTOPICENTRIES 9 + struct chanData { struct chanNode *channel; @@ -106,6 +109,8 @@ struct chanData unsigned short lvlOpts[NUM_LEVEL_OPTIONS]; unsigned char chOpts[NUM_CHAR_OPTIONS]; + char *advtopic[9]; + struct userData *users; struct banData *bans; struct dict *notes;