+static int check_userbot_rejoin(struct UserNode *user) {
+ if(!(user->flags & USERFLAG_ISAUTHED)) return 0;
+ char tmp[MAXLEN];
+ sprintf(tmp, "General.UserBots.%s.enabled", user->auth);
+ if(!get_int_field(tmp))
+ return 0;
+ sprintf(tmp, "General.UserBots.%s.nicks", user->auth);
+ char *nicks = get_string_field(tmp);
+ if(nicks) {
+ char *cnick = nicks;
+ int matching_nick = 0;
+ do {
+ nicks = strchr(cnick, ',');
+ if(nicks)
+ *nicks = '\0';
+ if(!match(cnick, user->nick))
+ matching_nick = 1;
+ if(nicks) {
+ *nicks = ',';
+ nicks++;
+ }
+ } while((cnick = nicks) && !matching_nick);
+ if(!matching_nick)
+ return 0;
+ }
+ sprintf(tmp, "General.UserBots.%s.opless_part", user->auth);
+ if(!get_string_field(tmp))
+ return 0;
+ return 1;
+}
+
+static void free_rejoin_clients(struct ChanNode *chan, int rejoin) {
+ struct OplessRejoinBot *rejoin_bot, *next_rejoin_bot;
+ char tmp[MAXLEN];
+ int sourceid;
+ struct ClientSocket *bot;
+ for(rejoin_bot = chan->rejoin_bots; rejoin_bot; rejoin_bot = next_rejoin_bot) {
+ next_rejoin_bot = rejoin_bot->next;
+ if(rejoin) {
+ if(rejoin_bot->is_client) {
+ putsock(rejoin_bot->bot.client, "JOIN %s", chan->name);
+ } else {
+ sprintf(tmp, "General.UserBots.%s.sourcebot", rejoin_bot->bot.userbot->auth);
+ if(get_string_field(tmp)) {
+ sourceid = resolve_botalias(get_string_field(tmp));
+ if(sourceid == -1)
+ sourceid = 0;
+ } else
+ sourceid = 0;
+ bot = getChannelBot(NULL, sourceid);
+ if(!bot)
+ bot = getChannelBot(NULL, 0);
+ sprintf(tmp, "General.UserBots.%s.opless_join", rejoin_bot->bot.userbot->auth);
+ if(get_string_field(tmp))
+ putsock(bot, get_string_field(tmp), rejoin_bot->bot.userbot->nick, chan->name);
+ }
+ }
+ if(!rejoin_bot->is_client) {
+ free(rejoin_bot->bot.userbot->nick);
+ free(rejoin_bot->bot.userbot->auth);
+ free(rejoin_bot->bot.userbot);
+ }
+ free(rejoin_bot);
+ }
+ if(chan->rejoin_timeout)
+ timeq_del(chan->rejoin_timeout);
+}
+
+static TIMEQ_CALLBACK(full_rejoin_timeout) {
+ struct ChanNode *chan = data;
+ chan->rejoin_timeout = NULL;
+ free_rejoin_clients(chan, 1);
+ chan->flags &= ~CHANFLAG_REJOINING;
+}
+
+static void check_full_rejoin(struct ChanNode *chan) {
+ struct ChanUser *chanuser;
+ char do_rejoin = 1;
+ int botcount = 0;
+ int userbots = 0;
+ for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+ if((chanuser->flags & CHANUSERFLAG_OPPED) || !(isBot(chanuser->user) || check_userbot_rejoin(chanuser->user))) {
+ do_rejoin = 0;
+ break;
+ }
+ botcount++;
+ if(!isBot(chanuser->user))
+ userbots++;
+ }
+ if(do_rejoin) {
+ struct OplessRejoinBot *rejoin_bot;
+ struct ClientSocket *bot, *chanbot = NULL;
+ chan->rejoin_bots = NULL;
+ for(bot = getBots(SOCKET_FLAG_READY, NULL); bot; bot = getBots(SOCKET_FLAG_READY, bot)) {
+ if(!isUserOnChan(bot->user, chan))
+ continue;
+ if(!chanbot && ((bot->flags & SOCKET_FLAG_PREFERRED) || !getBots(SOCKET_FLAG_READY, bot)))
+ chanbot = bot;
+ else {
+ rejoin_bot = malloc(sizeof(*rejoin_bot));
+ rejoin_bot->is_client = 1;
+ rejoin_bot->bot.client = bot;
+ rejoin_bot->next = chan->rejoin_bots;
+ chan->rejoin_bots = rejoin_bot;
+ putsock(bot, "PART %s :rejoining", chan->name);
+ }
+ }
+ if(userbots) {
+ char tmp[MAXLEN];
+ int sourceid;
+ for(chanuser = getChannelUsers(chan, NULL); chanuser; chanuser = getChannelUsers(chan, chanuser)) {
+ if(check_userbot_rejoin(chanuser->user)) {
+ rejoin_bot = malloc(sizeof(*rejoin_bot));
+ rejoin_bot->is_client = 0;
+ rejoin_bot->bot.userbot = malloc(sizeof(struct OplessRejoinUserbot));
+ rejoin_bot->bot.userbot->nick = strdup(chanuser->user->nick);
+ rejoin_bot->bot.userbot->auth = strdup(chanuser->user->auth);
+ rejoin_bot->next = chan->rejoin_bots;
+ chan->rejoin_bots = rejoin_bot;
+ sprintf(tmp, "General.UserBots.%s.sourcebot", chanuser->user->auth);
+ if(get_string_field(tmp)) {
+ sourceid = resolve_botalias(get_string_field(tmp));
+ if(sourceid == -1)
+ sourceid = 0;
+ } else
+ sourceid = 0;
+ bot = getChannelBot(NULL, sourceid);
+ if(!bot)
+ bot = getChannelBot(NULL, 0);
+ sprintf(tmp, "General.UserBots.%s.opless_part", chanuser->user->auth);
+ putsock(bot, get_string_field(tmp), chanuser->user->nick, chan->name);
+ }
+ }
+ }
+
+ if(botcount == 1) {
+ //we're alone
+ free(chan->rejoin_bots);
+ putsock(chanbot, "PART %s :magic hop", chan->name);
+ putsock(chanbot, "JOIN %s", chan->name);
+ } else {
+ chan->flags |= CHANFLAG_REJOINING;
+ chan->rejoin_timeout = timeq_add(10, 0, full_rejoin_timeout, chan);
+ }
+ }
+}
+