--- /dev/null
+
+#include "cmd_neonserv.h"
+
+/*
+* argv[0-*] nick[,*auth[,*!*@mask[...]]]
+*/
+struct neonserv_cmd_unban_cache {
+ struct ClientSocket *client, *textclient;
+ struct UserNode *user;
+ struct ChanNode *chan;
+ struct Event *event;
+ struct ModeBuffer *modeBuf;
+ int provided_masks, done_masks, pending_whos, unbanned_masks;
+};
+
+static USERAUTH_CALLBACK(neonserv_cmd_unban_userauth_lookup);
+static void neonserv_cmd_unban_nick(struct neonserv_cmd_unban_cache *cache, struct UserNode *user);
+static void neonserv_cmd_unban_mask(struct neonserv_cmd_unban_cache *cache, char *mask);
+static void neonserv_cmd_unban_finish(struct neonserv_cmd_unban_cache *cache);
+
+CMD_BIND(neonserv_cmd_unban) {
+ char *mask, *nextmask;
+ struct ModeBuffer *modeBuf;
+ modeBuf = initModeBuffer(client, chan);
+ nextmask = merge_argv_char(argv, 0, argc, ',');
+ struct neonserv_cmd_unban_cache *cache = malloc(sizeof(*cache));
+ if (!cache) {
+ perror("malloc() failed");
+ return;
+ }
+ cache->client = client;
+ cache->textclient = getTextBot();
+ cache->user = user;
+ cache->chan = chan;
+ cache->event = event;
+ cache->modeBuf = modeBuf;
+ cache->done_masks = 0;
+ cache->provided_masks = 0;
+ cache->unbanned_masks = 0;
+ while((mask = nextmask)) {
+ nextmask = strstr(mask, ",");
+ if(nextmask) {
+ *nextmask = '\0';
+ nextmask++;
+ }
+ cache->provided_masks++;
+ if(is_valid_nick(mask)) {
+ struct UserNode *cuser = getUserByNick(mask);
+ if(!cuser) {
+ cuser = createTempUser(mask);
+ cuser->flags |= USERFLAG_ISTMPUSER;
+ get_userauth(cuser, neonserv_cmd_unban_userauth_lookup, cache);
+ cache->pending_whos++;
+ } else {
+ neonserv_cmd_unban_nick(cache, cuser);
+ }
+ } else {
+ neonserv_cmd_unban_mask(cache, mask);
+ }
+ }
+ if(!cache->pending_whos)
+ neonserv_cmd_unban_finish(cache);
+}
+
+static USERAUTH_CALLBACK(neonserv_cmd_unban_userauth_lookup) {
+ struct neonserv_cmd_unban_cache *cache = data;
+ cache->pending_whos--;
+ if(user)
+ neonserv_cmd_unban_nick(cache, user);
+ else
+ neonserv_cmd_unban_mask(cache, user_nick);
+ if(!cache->pending_whos)
+ neonserv_cmd_unban_finish(cache);
+}
+
+static void neonserv_cmd_unban_nick(struct neonserv_cmd_unban_cache *cache, struct UserNode *user) {
+ int matches = 0;
+ struct BanNode *ban;
+ char usermask[NICKLEN+USERLEN+HOSTLEN+3];
+ sprintf(usermask, "%s!%s@%s", user->nick, user->ident, user->host);
+ for(ban = cache->chan->bans; ban; ban = ban->next) {
+ if(!match(ban->mask, usermask)) {
+ modeBufferUnban(cache->modeBuf, ban->mask);
+ cache->unbanned_masks++;
+ matches++;
+ }
+ }
+ if(matches)
+ cache->done_masks++;
+}
+
+static void neonserv_cmd_unban_mask(struct neonserv_cmd_unban_cache *cache, char *mask) {
+ char banmask[NICKLEN+USERLEN+HOSTLEN+3];
+ int matches = 0;
+ struct BanNode *ban;
+ mask = make_banmask(mask, banmask);
+ for(ban = cache->chan->bans; ban; ban = ban->next) {
+ if(!match(mask, ban->mask)) {
+ modeBufferUnban(cache->modeBuf, ban->mask);
+ cache->unbanned_masks++;
+ matches++;
+ }
+ }
+ if(matches)
+ cache->done_masks++;
+ else {
+ for(ban = cache->chan->bans; ban; ban = ban->next) {
+ if(!match(ban->mask, mask)) {
+ reply(cache->textclient, cache->user, "NS_DELBAN_BANNED_BY", mask, ban->mask);
+ break;
+ }
+ }
+ }
+}
+
+static void neonserv_cmd_unban_finish(struct neonserv_cmd_unban_cache *cache) {
+ freeModeBuffer(cache->modeBuf);
+ if(cache->done_masks == cache->provided_masks)
+ reply(cache->textclient, cache->user, "NS_UNBAN_DONE", cache->unbanned_masks, cache->chan->name);
+ else
+ reply(cache->textclient, cache->user, "NS_UNBAN_FAIL", cache->client->user->nick);
+ if(cache->done_masks)
+ logEvent(cache->event);
+ free(cache);
+}
+