X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fchanserv.c;h=d99ed500156bbe6f9c9309562920ba34fe271ee2;hb=c7ac1f35024b9921d892bb47e1a532baffaf9bf3;hp=1dbf346c3cfb528d1a47d55b956ea7bae36aa18a;hpb=f5fdab41806c61c02fec52467237df541e640570;p=srvx.git diff --git a/src/chanserv.c b/src/chanserv.c index 1dbf346..d99ed50 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" }, @@ -432,6 +435,11 @@ static const struct message_entry msgtab[] = { { "CSMSG_CHANNEL_REGISTERED", "$bRegistered: $b%s ago." }, { "CSMSG_CHANNEL_VISITED", "$bVisited: $b%s ago." }, + { "CSMSG_CHANNEL_OWNERSHIP_HISTORY", "Ownership transfer history for %s" }, + { "CSMSG_CHANNEL_OWNERSHIP_STAFF_REASON", " from %s to %s (%d access) by %s on %s (Reason: %s)" }, + { "CSMSG_CHANNEL_OWNERSHIP_STAFF", " from %s to %s (%d access) by %s on %s" }, + { "CSMSG_CHANNEL_OWNERSHIP_NORMAL", " from %s to %s (%d access) on %s" }, + { "CSMSG_PEEK_INFO", "$b%s$b Status:" }, { "CSMSG_PEEK_TOPIC", "$bTopic: $b%s" }, { "CSMSG_PEEK_MODES", "$bModes: $b%s" }, @@ -1224,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)); @@ -1240,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; @@ -1431,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: @@ -1466,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; @@ -4150,6 +4167,8 @@ cmd_list_users(struct userNode *user, struct chanNode *channel, unsigned int arg ary[1] = uData->handle->handle; if(uData->present) ary[2] = "Here"; + else if(HANDLE_FLAGGED(uData->handle, NETWORK)) + ary[2] = "Here"; else if(!uData->seen) ary[2] = "Never"; else @@ -4157,6 +4176,12 @@ cmd_list_users(struct userNode *user, struct chanNode *channel, unsigned int arg ary[2] = strdup(ary[2]); if(IsUserSuspended(uData)) ary[3] = "Suspended"; + else if(HANDLE_FLAGGED(uData->handle, OPER)) + ary[3] = "Operator"; + else if(HANDLE_FLAGGED(uData->handle, HELPING)) + ary[3] = "Staff"; + else if(HANDLE_FLAGGED(uData->handle, NETWORK)) + ary[3] = "Network"; else if(HANDLE_FLAGGED(uData->handle, FROZEN)) ary[3] = "Vacation"; else if(HANDLE_FLAGGED(uData->handle, BOT)) @@ -4318,8 +4343,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 @@ -4357,30 +4408,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+1); + 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; + } + 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 */ + if(!*ptr) break; + default: + new_topic[dpos++] = *ptr; + ptr++; + break; + } + } + } 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); @@ -5794,6 +5911,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; @@ -8222,6 +8344,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)) @@ -8494,6 +8626,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; @@ -8799,6 +8941,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);