static void join_notes(char *nick, char *uhost, char *handle, char *par) { int i = -1, j; struct chanset_t *chan = chanset; if (notify_onjoin) { /* drummer */ for (j = 0; j < dcc_total; j++) if ((dcc[j].type->flags & DCT_CHAT) && (!egg_strcasecmp(dcc[j].nick, handle))) return; /* They already know they have notes */ while (chan) { if (ismember(chan, nick)) return; /* They already know they have notes */ chan = chan->next; } i = num_notes(handle); if (i) { dprintf(DP_HELP, NOTES_WAITING_NOTICE, nick, i, (i == 1) ? "" : "s", botname); dprintf(DP_HELP, "NOTICE %s :%s /MSG %s NOTES <pass> INDEX\n", nick, NOTES_FORLIST, botname); } } }
struct chanset_t* find_common_opped_chan(bd::String nick) { for (struct chanset_t* chan = chanset; chan; chan = chan->next) { if (channel_active(chan) && (me_op(chan) || me_voice(chan))) { if (ismember(chan, nick.c_str())) return chan; } } return NULL; }
/** * Remove an elementfrom the set. Running time O(1). * Warning Using this method moves the last inserted element * into the position of the removed element. * Breaking the insertion order invariant - if you rely on that. */ void remove(unsigned int i){ if(!ismember(i)){ return; } unsigned int j = dense[n-1]; dense[sparse[i]] = j; sparse[j] = sparse[i]; n--; }
/* * Helper function that abort() on unexpected errors. * The expected error set is a zero-terminated array of scf_error_t */ static int check_scf_error(scf_error_t e, const scf_error_t *errs) { if (ismember(e, errs)) return (1); assert(0); abort(); /*NOTREACHED*/ }
/* Check if I am a halfop. Returns boolean 1 or 0. */ static int me_halfop(struct chanset_t *chan) { memberlist *mx = NULL; mx = ismember(chan, botname); if (!mx) return 0; if (chan_hashalfop(mx)) return 1; else return 0; }
/* Check whether I'm voice. Returns boolean 1 or 0. */ static int me_voice(struct chanset_t *chan) { memberlist *mx; mx = ismember(chan, botname); if (!mx) return 0; if (chan_hasvoice(mx)) return 1; else return 0; }
/* onanychan(): * checks if the given nickname is on any of the bot's chans. */ static struct chanset_t *onanychan(char *nick) { struct chanset_t *ch; memberlist *m; for (ch = chanset; ch; ch = ch->next) { m = ismember(ch, nick); if (m && !chan_issplit(m)) return ch; } return NULL; }
static int onchan(char *nick, char *chan) { struct chanset_t *ch; memberlist *m; ch = findchan_by_dname(chan); if (!ch) return 0; m = ismember(ch, nick); if (!m) return 0; else if (chan_issplit(m)) return 0; else return 1; }
char * samechans(const char *nick, const char *delim) { static char ret[1024] = ""; struct chanset_t *chan = NULL; ret[0] = 0; /* may be filled from last time */ for (chan = chanset; chan; chan = chan->next) { if (ismember(chan, nick)) { strlcat(ret, chan->dname, sizeof(ret)); strlcat(ret, delim, sizeof(ret)); } } return ret; }
/* Expire mask originally set by `who' on `chan'? * * We might not want to expire masks in all cases, as other bots * often tend to immediately reset masks they've listed in their * internal ban list, making it quite senseless for us to remove * them in the first place. * * Returns 1 if a mask on `chan' by `who' may be expired and 0 if * not. */ static int expired_mask(struct chanset_t *chan, char *who) { memberlist *m, *m2; char buf[UHOSTLEN], *snick, *sfrom; struct userrec *u; /* Always expire masks, regardless of who set it? */ if (force_expire) return 1; strcpy(buf, who); sfrom = buf; snick = splitnick(&sfrom); if (!snick[0]) return 1; m = ismember(chan, snick); if (!m) for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next) if (!egg_strcasecmp(sfrom, m2->userhost)) { m = m2; break; } if (!m || !chan_hasop(m) || !rfc_casecmp(m->nick, botname)) return 1; /* At this point we know the person/bot who set the mask is currently * present in the channel and has op. */ if (m->user) u = m->user; else { simple_sprintf(buf, "%s!%s", m->nick, m->userhost); u = get_user_by_host(buf); } /* Do not expire masks set by bots. */ if (u && u->flags & USER_BOT) return 0; else return 1; }
static void schan_members_join(struct llist_header *head, char *nick, char *uhost, char *user, char *chan) { struct stats_member *m; char *host; #ifndef NO_EGG struct chanset_t *eggchan; #endif m = schan_members_create(); m->nick = nmalloc(strlen(nick) + 1); strcpy(m->nick, nick); m->uhost = nmalloc(strlen(uhost) + 1); strcpy(m->uhost, uhost); m->joined = now; if (user) { m->user = findsuser_by_name(user); if (!m->user) { m->user = addsuser(user, now, now); debug1("Stats.Mod: Created suserrec for %s.", user); } } else { host = nmalloc(strlen(nick) + 1 + strlen(uhost) + 1); sprintf(host, "%s!%s", nick, uhost); m->user = findsuser(host); nfree(host); } if (m->user) { m->user->laston = now; m->stats = findlocstats(chan, m->user->user); if (!m->stats) m->stats = initstats(chan, m->user->user); } #ifndef NO_EGG eggchan = findchan_by_dname(chan); if (chan) m->eggmember = ismember(eggchan, nick); if (!m->eggmember) debug2("Warning[stats.mod]: Couldn't find eggmember for %s in %s.", nick, chan); #endif llist_append(head, (void *) m); }
BOOLEAN ismemberdata(SYMBOL *sp) { return !isfunction(sp->tp) && ismember(sp); }
/** * Adding a member to the set requires updating both of these arrays: * this should be constant time. */ inline void insert(unsigned int i){ if (!ismember(i)){ insert_new(i); } }
int _setargv(int *argc, char ***argv) { register int nargc; /* New arguments counter */ char **nargv; /* New arguments pointers */ register int i, j; int asize; /* argv array size */ char *arg; char lib[256]; _errnum = 0; nargc = 0; /* Initialise counter, size counter */ asize = *argc; /* and new argument vector to the */ /* current argv array size */ if ((nargv = (char **) calloc((size_t) *argc, sizeof (void *))) != NULL) { /* For each initial argument */ for (i = 0; i < *argc; i++) { arg = (*argv)[i]; #ifdef DEBUG fprintf(stderr, "checking arg: %s", arg); #endif if (i == 0 || *arg == '-' || ! ismember(arg)) { /* if it begins with a dash or doesn't include * a library name simply add it to the new array */ if (! (asize = allocarg(nargc, asize, &nargv, arg))) return 0; /* Not enough memory */ nargc++; } else { short insert; strcpy(lib, libname(arg)); /* add library name if necessary */ for (j = 2, insert = 1; i < nargc; i++) { if (ismember(nargv[i]) && ! strcmp(lib, libname(nargv[i]))) { insert = 0; break; } } if (insert) { #ifdef DEBUG fprintf(stderr, "inserting lib %s ", lib); #endif if (! (asize = allocarg(nargc, asize, &nargv, lib))) return 0; /* Not enough memory */ nargc++; } /* add file name */ #ifdef DEBUG fprintf(stderr, "inserting file %s", arg); #endif if (! (asize = allocarg(nargc, asize, &nargv, arg))) return 0; /* Not enough memory */ nargc++; } #ifdef DEBUG fprintf(stderr, "\n"); #endif } /* Update caller's parameters */ *argc = nargc; *argv = nargv; /* and sign on success */ return nargc; } /* If it is not possible to allocate initial array, sign on error */ _errnum = ENOMEM; return 0; }
static int msg_op(char *nick, char *host, struct userrec *u, char *par) { struct chanset_t *chan = NULL; char *pass = NULL; struct flag_record fr = {FR_GLOBAL | FR_CHAN, 0, 0, 0 }; if (match_my_nick(nick)) return BIND_RET_BREAK; pass = newsplit(&par); bd::String msg; if (homechan[0]) { struct chanset_t *hchan = NULL; hchan = findchan_by_dname(homechan); if (hchan && channel_active(hchan) && !ismember(hchan, nick)) { putlog(LOG_CMDS, "*", "(%s!%s) !*! failed OP %s (not in %s)", nick, host, par, homechan); if (par[0]) msg = bd::String::printf("---- (%s!%s) attempted to OP for %s but is not currently in %s.", nick, host, par, homechan); else msg = bd::String::printf("---- (%s!%s) attempted to OP but is not currently in %s.", nick, host, homechan); privmsg(homechan, msg.c_str(), DP_SERVER); return BIND_RET_BREAK; } } if (u_pass_match(u, pass)) { if (!u_pass_match(u, "-")) { if (par[0]) { chan = findchan_by_dname(par); if (chan && channel_active(chan)) { get_user_flagrec(u, &fr, par, chan); if (chk_op(fr, chan)) { if (do_op(nick, chan, 0, 1)) { stats_add(u, 0, 1); putlog(LOG_CMDS, "*", "(%s!%s) !%s! OP %s", nick, host, u->handle, par); if (manop_warn && chan->manop) { msg = bd::String::printf("%s is currently set to punish for manual op.", chan->dname); notice(nick, msg.c_str(), DP_HELP); } } } return BIND_RET_BREAK; } } else { int stats = 0; for (chan = chanset; chan; chan = chan->next) { get_user_flagrec(u, &fr, chan->dname, chan); if (chk_op(fr, chan)) { if (do_op(nick, chan, 0, 1)) { stats++; if (manop_warn && chan->manop) { msg = bd::String::printf("%s is currently set to punish for manual op.", chan->dname); notice(nick, msg.c_str(), DP_HELP); } } } } putlog(LOG_CMDS, "*", "(%s!%s) !%s! OP", nick, host, u->handle); if (stats) stats_add(u, 0, 1); return BIND_RET_BREAK; } } } putlog(LOG_CMDS, "*", "(%s!%s) !*! failed OP", nick, host); return BIND_RET_BREAK; }
static int gotmode(char *from, char *origmsg) { char *nick, *ch, *op, *chg, *msg; char s[UHOSTLEN], buf[511]; char ms2[3]; int z; struct userrec *u; memberlist *m; struct chanset_t *chan; strncpy(buf, origmsg, 510); buf[510] = 0; msg = buf; /* Usermode changes? */ if (msg[0] && (strchr(CHANMETA, msg[0]) != NULL)) { ch = newsplit(&msg); chg = newsplit(&msg); reversing = 0; chan = findchan(ch); if (!chan) { putlog(LOG_MISC, "*", CHAN_FORCEJOIN, ch); dprintf(DP_SERVER, "PART %s\n", ch); } else if (channel_active(chan) || channel_pending(chan)) { z = strlen(msg); if (msg[--z] == ' ') /* I hate cosmetic bugs :P -poptix */ msg[z] = 0; putlog(LOG_MODES, chan->dname, "%s: mode change '%s %s' by %s", ch, chg, msg, from); u = get_user_by_host(from); get_user_flagrec(u, &user, ch); nick = splitnick(&from); m = ismember(chan, nick); if (m) m->last = now; if (m && channel_active(chan) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m))) && !(glob_friend(user) || chan_friend(user) || (channel_dontkickops(chan) && (chan_op(user) || (glob_op(user) && !chan_deop(user))))) && !match_my_nick(nick)) { if (chan_fakeop(m) || chan_fakehalfop(m)) { putlog(LOG_MODES, ch, CHAN_FAKEMODE, ch); dprintf(DP_MODE, "KICK %s %s :%s\n", ch, nick, CHAN_FAKEMODE_KICK); m->flags |= SENTKICK; reversing = 1; } else if (!chan_hasop(m) && !chan_hashalfop(m) && !channel_nodesynch(chan)) { putlog(LOG_MODES, ch, CHAN_DESYNCMODE, ch); dprintf(DP_MODE, "KICK %s %s :%s\n", ch, nick, CHAN_DESYNCMODE_KICK); m->flags |= SENTKICK; reversing = 1; } } ms2[0] = '+'; ms2[2] = 0; while ((ms2[1] = *chg)) { int todo = 0; switch (*chg) { case '+': ms2[0] = '+'; break; case '-': ms2[0] = '-'; break; case 'i': todo = CHANINV; if (!nick[0] && bounce_modes) reversing = 1; break; case 'p': todo = CHANPRIV; if (!nick[0] && bounce_modes) reversing = 1; break; case 's': todo = CHANSEC; if (!nick[0] && bounce_modes) reversing = 1; break; case 'm': todo = CHANMODER; if (!nick[0] && bounce_modes) reversing = 1; break; case 'c': todo = CHANNOCLR; if (!nick[0] && bounce_modes) reversing = 1; break; case 'C': todo = CHANNOCTCP; if (!nick[0] && bounce_modes) reversing = 1; break; case 'R': todo = CHANREGON; if (!nick[0] && bounce_modes) reversing = 1; break; case 'M': todo = CHANMODREG; if (!nick[0] && bounce_modes) reversing = 1; break; case 'r': todo = CHANLONLY; if (!nick[0] && bounce_modes) reversing = 1; break; case 'D': todo = CHANDELJN; if (!nick[0] && bounce_modes) reversing = 1; break; case 'u': todo = CHANSTRIP; if (!nick[0] && bounce_modes) reversing = 1; break; case 'N': todo = CHANNONOTC; if (!nick[0] && bounce_modes) reversing = 1; break; case 'T': todo = CHANNOAMSG; if (!nick[0] && bounce_modes) reversing = 1; break; case 'd': todo = CHANINVIS; break; case 't': todo = CHANTOPIC; if (!nick[0] && bounce_modes) reversing = 1; break; case 'n': todo = CHANNOMSG; if (!nick[0] && bounce_modes) reversing = 1; break; case 'a': todo = CHANANON; if (!nick[0] && bounce_modes) reversing = 1; break; case 'q': todo = CHANQUIET; if (!nick[0] && bounce_modes) reversing = 1; break; case 'l': if (!nick[0] && bounce_modes) reversing = 1; if (ms2[0] == '-') { check_tcl_mode(nick, from, u, chan->dname, ms2, ""); /* The Tcl proc might have modified/removed the chan or user */ if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL))) return 0; if (channel_active(chan)) { if (reversing && (chan->channel.maxmembers != 0)) { simple_sprintf(s, "%d", chan->channel.maxmembers); add_mode(chan, '+', 'l', s); } else if ((chan->limit_prot != 0) && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) { simple_sprintf(s, "%d", chan->limit_prot); add_mode(chan, '+', 'l', s); } } chan->channel.maxmembers = 0; } else { op = newsplit(&msg); fixcolon(op); if (op == '\0') break; chan->channel.maxmembers = atoi(op); check_tcl_mode(nick, from, u, chan->dname, ms2, int_to_base10(chan->channel.maxmembers)); /* The Tcl proc might have modified/removed the chan or user */ if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL))) return 0; if (channel_pending(chan)) break; if ((reversing && !(chan->mode_pls_prot & CHANLIMIT)) || ((chan->mode_mns_prot & CHANLIMIT) && !glob_master(user) && !chan_master(user))) add_mode(chan, '-', 'l', ""); if ((chan->limit_prot != chan->channel.maxmembers) && (chan->mode_pls_prot & CHANLIMIT) && (chan->limit_prot != 0) && !glob_master(user) && !chan_master(user)) { simple_sprintf(s, "%d", chan->limit_prot); add_mode(chan, '+', 'l', s); } } break; case 'k': if (ms2[0] == '+') chan->channel.mode |= CHANKEY; else chan->channel.mode &= ~CHANKEY; op = newsplit(&msg); fixcolon(op); if (op == '\0') { break; } check_tcl_mode(nick, from, u, chan->dname, ms2, op); /* The Tcl proc might have modified/removed the chan or user */ if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL))) return 0; if (ms2[0] == '+') { set_key(chan, op); if (channel_active(chan)) got_key(chan, nick, from, op); } else { if (channel_active(chan)) { if (reversing && chan->channel.key[0]) add_mode(chan, '+', 'k', chan->channel.key); else if (chan->key_prot[0] && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) add_mode(chan, '+', 'k', chan->key_prot); } set_key(chan, NULL); } break; case 'o': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_op(chan, nick, from, op, u, &user); else got_deop(chan, nick, from, op, u); break; case 'h': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_halfop(chan, nick, from, op, u, &user); else got_dehalfop(chan, nick, from, op, u); break; case 'v': op = newsplit(&msg); fixcolon(op); m = ismember(chan, op); if (!m) { if (channel_pending(chan)) break; putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, op); chan->status |= CHAN_PEND; refresh_who_chan(chan->name); } else { simple_sprintf(s, "%s!%s", m->nick, m->userhost); get_user_flagrec(m->user ? m->user : get_user_by_host(s), &victim, chan->dname); if (ms2[0] == '+') { m->flags &= ~SENTVOICE; m->flags |= CHANVOICE; check_tcl_mode(nick, from, u, chan->dname, ms2, op); if (!(chan = modebind_refresh(ch, from, &user, s, &victim))) return 0; if (channel_active(chan) && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) { if (chan_quiet(victim) || (glob_quiet(victim) && !chan_voice(victim))) add_mode(chan, '-', 'v', op); else if (reversing) add_mode(chan, '-', 'v', op); } } else { m->flags &= ~SENTDEVOICE; m->flags &= ~CHANVOICE; check_tcl_mode(nick, from, u, chan->dname, ms2, op); if (!(chan = modebind_refresh(ch, from, &user, s, &victim))) return 0; if (channel_active(chan) && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) { if ((channel_autovoice(chan) && !chan_quiet(victim) && (chan_voice(victim) || glob_voice(victim))) || (!chan_quiet(victim) && (glob_gvoice(victim) || chan_gvoice(victim)))) add_mode(chan, '+', 'v', op); else if (reversing) add_mode(chan, '+', 'v', op); } } } break; case 'b': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_ban(chan, nick, from, op, ch, u); else got_unban(chan, nick, from, op, ch, u); break; case 'e': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_exempt(chan, nick, from, op, ch, u); else got_unexempt(chan, nick, from, op, ch, u); break; case 'I': op = newsplit(&msg); fixcolon(op); if (ms2[0] == '+') got_invite(chan, nick, from, op, ch, u); else got_uninvite(chan, nick, from, op, ch, u); break; } if (todo) { check_tcl_mode(nick, from, u, chan->dname, ms2, ""); if (!(chan = modebind_refresh(ch, from, &user, NULL, NULL))) return 0; if (ms2[0] == '+') chan->channel.mode |= todo; else chan->channel.mode &= ~todo; if (channel_active(chan)) { if ((((ms2[0] == '+') && (chan->mode_mns_prot & todo)) || ((ms2[0] == '-') && (chan->mode_pls_prot & todo))) && !glob_master(user) && !chan_master(user) && !match_my_nick(nick)) add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, ""); else if (reversing && ((ms2[0] == '+') || (chan->mode_pls_prot & todo)) && ((ms2[0] == '-') || (chan->mode_mns_prot & todo))) add_mode(chan, ms2[0] == '+' ? '-' : '+', *chg, ""); } } chg++; } if (!me_op(chan) && !nick[0]) chan->status |= CHAN_ASKEDMODES; } } return 0; }
/* Dependant on revenge_mode, punish the offender. */ static void punish_badguy(struct chanset_t *chan, char *whobad, struct userrec *u, char *badnick, char *victim, int mevictim, int type) { char reason[1024], ct[81], *kick_msg; memberlist *m; struct flag_record fr = { FR_GLOBAL | FR_CHAN, 0, 0, 0, 0, 0 }; m = ismember(chan, badnick); if (!m) return; get_user_flagrec(u, &fr, chan->dname); /* Get current time into a string */ egg_strftime(ct, 7, "%d %b", localtime(&now)); /* Put together log and kick messages */ reason[0] = 0; switch (type) { case REVENGE_KICK: kick_msg = IRC_KICK_PROTECT; simple_sprintf(reason, "kicked %s off %s", victim, chan->dname); break; case REVENGE_DEOP: simple_sprintf(reason, "deopped %s on %s", victim, chan->dname); kick_msg = IRC_DEOP_PROTECT; break; default: kick_msg = "revenge!"; } putlog(LOG_MISC, chan->dname, "Punishing %s (%s)", badnick, reason); /* Set the offender +d */ if ((chan->revenge_mode > 0) && !(chan_deop(fr) || glob_deop(fr))) { char s[UHOSTLEN], s1[UHOSTLEN]; memberlist *mx = NULL; /* Removing op */ if (chan_op(fr) || (glob_op(fr) && !chan_deop(fr))) { fr.match = FR_CHAN; if (chan_op(fr)) fr.chan &= ~USER_OP; else fr.chan |= USER_DEOP; set_user_flagrec(u, &fr, chan->dname); putlog(LOG_MISC, "*", "No longer opping %s[%s] (%s)", u->handle, whobad, reason); } /* ... or just setting to deop */ else if (u) { /* In the user list already, cool :) */ fr.match = FR_CHAN; fr.chan |= USER_DEOP; set_user_flagrec(u, &fr, chan->dname); simple_sprintf(s, "(%s) %s", ct, reason); putlog(LOG_MISC, "*", "Now deopping %s[%s] (%s)", u->handle, whobad, s); } /* ... or creating new user and setting that to deop */ else { strcpy(s1, whobad); maskaddr(s1, s, chan->ban_type); strcpy(s1, badnick); /* If that handle exists use "badX" (where X is an increasing number) * instead. */ while (get_user_by_handle(userlist, s1)) { if (!strncmp(s1, "bad", 3)) { int i; i = atoi(s1 + 3); simple_sprintf(s1 + 3, "%d", i + 1); } else strcpy(s1, "bad1"); /* Start with '1' */ } userlist = adduser(userlist, s1, s, "-", 0); fr.match = FR_CHAN; fr.chan = USER_DEOP; fr.udef_chan = 0; u = get_user_by_handle(userlist, s1); if ((mx = ismember(chan, badnick))) mx->user = u; set_user_flagrec(u, &fr, chan->dname); simple_sprintf(s, "(%s) %s (%s)", ct, reason, whobad); set_user(&USERENTRY_COMMENT, u, (void *) s); putlog(LOG_MISC, "*", "Now deopping %s (%s)", whobad, reason); } } /* Always try to deop the offender */ if (!mevictim) add_mode(chan, '-', 'o', badnick); /* Ban. Should be done before kicking. */ if (chan->revenge_mode > 2) { char s[UHOSTLEN], s1[UHOSTLEN]; splitnick(&whobad); maskaddr(whobad, s1, chan->ban_type); simple_sprintf(s, "(%s) %s", ct, reason); u_addban(chan, s1, botnetnick, s, now + (60 * chan->ban_time), 0); if (!mevictim && HALFOP_CANDOMODE('b')) { add_mode(chan, '+', 'b', s1); flush_mode(chan, QUICK); } } /* Kick the offender */ if (!mevictim && (chan->revenge_mode > 1) && (!channel_dontkickops(chan) || (!chan_op(fr) && (!glob_op(fr) || chan_deop(fr)))) && !chan_sentkick(m) && (me_op(chan) || (me_halfop(chan) && !chan_hasop(m) && (strchr(NOHALFOPS_MODES, 'b') == NULL)))) { dprintf(DP_MODE, "KICK %s %s :%s\n", chan->name, badnick, kick_msg); m->flags |= SENTKICK; } }
static void do_seen(int idx, char *prefix, char *nick, char *hand, char *channel, char *text) { char stuff[512], word1[512], word2[512], whotarget[512], object[512], whoredirect[512], *oix, *lastonplace = 0; struct userrec *urec; struct chanset_t *chan; struct laston_info *li; struct chanuserrec *cr; memberlist *m = NULL; int onchan = 0, i; long tv; time_t laston = 0, work; whotarget[0] = 0; whoredirect[0] = 0; object[0] = 0; /* Was ANYONE specified */ if (!text[0]) { dprintf(idx, "%sUm, %s, it might help if you ask me about _someone_...\n", prefix, nick); return; } wordshift(word1, text); oix = strchr(word1, '\''); /* Have we got a NICK's target? */ if (oix == word1) return; /* Skip anything starting with ' */ if (oix && *oix && ((oix[1] && (oix[1] == 's' || oix[1] == 'S') && !oix[2]) || (!oix[1] && (oix[-1] == 's' || oix[-1] == 'z' || oix[-1] == 'x' || oix[-1] == 'S' || oix[-1] == 'Z' || oix[-1] == 'X')))) { strncpy(object, word1, oix - word1); object[oix - word1] = 0; wordshift(word1, text); if (!word1[0]) { dprintf(idx, "%s%s's what, %s?\n", prefix, object, nick); return; } urec = get_user_by_handle(userlist, object); if (!urec) { chan = chanset; while (chan) { onchan = 0; m = ismember(chan, object); if (m) { onchan = 1; sprintf(stuff, "%s!%s", object, m->userhost); urec = get_user_by_host(stuff); if (!urec || !egg_strcasecmp(object, urec->handle)) break; strcat(whoredirect, object); strcat(whoredirect, " is "); strcat(whoredirect, urec->handle); strcat(whoredirect, ", and "); strcpy(object, urec->handle); break; } chan = chan->next; } if (!onchan) { dprintf(idx, "%sI don't think I know who %s is, %s.\n", prefix, object, nick); return; } } if (!egg_strcasecmp(word1, "bf") || !egg_strcasecmp(word1, "boyfriend")) { strcpy(whotarget, getxtra(object, "BF")); if (whotarget[0]) { sprintf(whoredirect, "%s boyfriend is %s, and ", fixnick(object), whotarget); goto targetcont; } dprintf(idx, "%sI don't know who %s boyfriend is, %s.\n", prefix, fixnick(object), nick); return; } if (!egg_strcasecmp(word1, "gf") || !egg_strcasecmp(word1, "girlfriend")) { strcpy(whotarget, getxtra(object, "GF")); if (whotarget[0]) { sprintf(whoredirect, "%s girlfriend is %s, and ", fixnick(object), whotarget); goto targetcont; } dprintf(idx, "%sI don't know who %s girlfriend is, %s.\n", prefix, fixnick(object), nick); return; } dprintf(idx, "%sWhy are you bothering me with questions about %s %s, %s?\n", prefix, fixnick(object), word1, nick); return; } /* Keyword "my" */ if (!egg_strcasecmp(word1, "my")) { wordshift(word1, text); if (!word1[0]) { dprintf(idx, "%sYour what, %s?\n", prefix, nick); return; } /* Do I even KNOW the requestor? */ if (hand[0] == '*' || !hand[0]) { dprintf(idx, "%sI don't know you, %s, so I don't know about your %s.\n", prefix, nick, word1); return; } /* "my boyfriend" */ if (!egg_strcasecmp(word1, "boyfriend") || !egg_strcasecmp(word1, "bf")) { strcpy(whotarget, getxtra(hand, "BF")); if (whotarget[0]) { sprintf(whoredirect, "%s, your boyfriend is %s, and ", nick, whotarget); } else { dprintf(idx, "%sI didn't know you had a boyfriend, %s\n", prefix, nick); return; } } /* "my girlfriend" */ else if (!egg_strcasecmp(word1, "girlfriend") || !egg_strcasecmp(word1, "gf")) { strcpy(whotarget, getxtra(hand, "GF")); if (whotarget[0]) { sprintf(whoredirect, "%s, your girlfriend is %s, and ", nick, whotarget); } else { dprintf(idx, "%sI didn't know you had a girlfriend, %s\n", prefix, nick); return; } } else { dprintf(idx, "%sI don't know anything about your %s, %s.\n", prefix, word1, nick); return; } } /* "your" keyword */ else if (!egg_strcasecmp(word1, "your")) { wordshift(word1, text); /* "your admin" */ if (!egg_strcasecmp(word1, "owner") || !egg_strcasecmp(word1, "admin")) { if (admin[0]) { strcpy(word2, admin); wordshift(whotarget, word2); strcat(whoredirect, "My owner is "); strcat(whoredirect, whotarget); strcat(whoredirect, ", and "); if (!egg_strcasecmp(whotarget, hand)) { strcat(whoredirect, "that's YOU"); if (!egg_strcasecmp(hand, nick)) strcat(whoredirect, "!!!"); else { strcat(whoredirect, ", "); strcat(whoredirect, nick); strcat(whoredirect, "!"); } dprintf(idx, "%s%s\n", prefix, whoredirect); return; } } else { /* owner variable munged or not set */ dprintf(idx, "%sI don't seem to recall who my owner is right now...\n", prefix); return; } } else { /* no "your" target specified */ dprintf(idx, "%sLet's not get personal, %s.\n", prefix, nick); return; } } /* Check for keyword match in the internal table */ else if (match_trigger(word1)) { sprintf(word2, "%s%s\n", prefix, match_trigger(word1)); dprintf(idx, word2, nick); return; } /* Otherwise, make the target to the first word and continue */ else strcpy(whotarget, word1); targetcont: /* Looking for ones own nick? */ if (!rfc_casecmp(nick, whotarget)) { dprintf(idx, "%s%sLooking for yourself, eh %s?\n", prefix, whoredirect, nick); return; } /* Check if nick is on a channel */ chan = chanset; while (chan) { m = ismember(chan, whotarget); if (m) { onchan = 1; sprintf(word1, "%s!%s", whotarget, m->userhost); urec = get_user_by_host(word1); if (!urec || !egg_strcasecmp(whotarget, urec->handle)) break; strcat(whoredirect, whotarget); strcat(whoredirect, " is "); strcat(whoredirect, urec->handle); strcat(whoredirect, ", and "); break; } chan = chan->next; } /* Check if nick is on a channel by xref'ing to handle */ if (!onchan) { chan = chanset; while (chan) { m = chan->channel.member; while (m && m->nick[0]) { sprintf(word2, "%s!%s", m->nick, m->userhost); urec = get_user_by_host(word2); if (urec && !egg_strcasecmp(urec->handle, whotarget)) { onchan = 1; strcat(whoredirect, whotarget); strcat(whoredirect, " is "); strcat(whoredirect, m->nick); strcat(whoredirect, ", and "); strcpy(whotarget, m->nick); break; } m = m->next; } chan = chan->next; } } /* Check if the target was on the channel, but is netsplit */ chan = findchan_by_dname(channel); if (chan) { m = ismember(chan, whotarget); if (m && chan_issplit(m)) { dprintf(idx, "%s%s%s was just here, but got netsplit.\n", prefix, whoredirect, whotarget); return; } } /* Check if the target IS on the channel */ if (chan && m) { dprintf(idx, "%s%s%s is on the channel right now!\n", prefix, whoredirect, whotarget); return; } /* Target not on this channel. Check other channels */ chan = chanset; while (chan) { m = ismember(chan, whotarget); if (m && chan_issplit(m)) { dprintf(idx, "%s%s%s was just on %s, but got netsplit.\n", prefix, whoredirect, whotarget, chan->dname); return; } if (m) { dprintf(idx, "%s%s%s is on %s right now!\n", prefix, whoredirect, whotarget, chan->dname); return; } chan = chan->next; } /* Target isn't on any of my channels. */ /* See if target matches a handle in my userlist. */ urec = get_user_by_handle(userlist, whotarget); /* No match, then bail out */ if (!urec) { dprintf(idx, "%s%sI don't know who %s is.\n", prefix, whoredirect, whotarget); return; } /* We had a userlist match to a handle */ /* Is the target currently DCC CHAT to me on the botnet? */ for (i = 0; i < dcc_total; i++) { if (dcc[i].type->flags & DCT_CHAT) { if (!egg_strcasecmp(whotarget, dcc[i].nick)) { if (!rfc_casecmp(channel, dcc[i].u.chat->con_chan) && dcc[i].u.chat->con_flags & LOG_PUBLIC) { strcat(whoredirect, whotarget); strcat(whoredirect, " is 'observing' this channel right now from my party line!"); dprintf(idx, "%s%s\n", prefix, whoredirect); } else { dprintf(idx, "%s%s%s is linked to me via DCC CHAT right now!\n", prefix, whoredirect, whotarget); } return; } } } /* Target known, but nowhere to be seen. Give last IRC and botnet time */ wordshift(word1, text); if (!egg_strcasecmp(word1, "anywhere")) cr = NULL; else for (cr = urec->chanrec; cr; cr = cr->next) { if (!rfc_casecmp(cr->channel, channel)) { if (cr->laston) { laston = cr->laston; lastonplace = channel; break; } } } if (!cr) { li = get_user(&USERENTRY_LASTON, urec); if (!li || !li->lastonplace || !li->lastonplace[0]) { dprintf(idx, "%s%sI've never seen %s around.\n", prefix, whoredirect, whotarget); return; } lastonplace = li->lastonplace; laston = li->laston; } word1[0] = 0; word2[0] = 0; work = now - laston; if (work >= 86400) { tv = work / 86400; sprintf(word2, "%lu day%s, ", tv, (tv == 1) ? "" : "s"); work = work % 86400; } if (work >= 3600) { tv = work / 3600; sprintf(word2 + strlen(word2), "%lu hour%s, ", tv, (tv == 1) ? "" : "s"); work = work % 3600; } if (work >= 60) { tv = work / 60; sprintf(word2 + strlen(word2), "%lu minute%s, ", tv, (tv == 1) ? "" : "s"); } if (!word2[0] && (work < 60)) { strcpy(word2, "just moments ago!!"); } else { strcpy(word2 + strlen(word2) - 2, " ago."); } if (lastonplace[0] && (strchr(CHANMETA, lastonplace[0]) != NULL)) sprintf(word1, "on IRC channel %s", lastonplace); else if (lastonplace[0] == '@') sprintf(word1, "on %s", lastonplace + 1); else if (lastonplace[0] != 0) sprintf(word1, "on my %s", lastonplace); else strcpy(word1, "seen"); dprintf(idx, "%s%s%s was last %s %s\n", prefix, whoredirect, whotarget, word1, word2); }
/* Queue a channel mode change */ static void real_add_mode(struct chanset_t *chan, char plus, char mode, char *op) { int i, type, modes, l; masklist *m; memberlist *mx; char s[21]; /* Some IRCds do not allow halfops to set certain modes. The modes halfops * are not allowed to set can be changed in chan.h. */ #ifdef NO_HALFOP_CHANMODES if (!me_op(chan)) #else if (HALFOP_CANTDOMODE(mode)) #endif return; if (mode == 'o' || mode == 'h' || mode == 'v') { mx = ismember(chan, op); if (!mx) return; if (plus == '-' && mode == 'o') { if (chan_sentdeop(mx) || !chan_hasop(mx)) return; mx->flags |= SENTDEOP; } if (plus == '+' && mode == 'o') { if (chan_sentop(mx) || chan_hasop(mx)) return; mx->flags |= SENTOP; } if (plus == '-' && mode == 'h') { if (chan_sentdehalfop(mx) || !chan_hashalfop(mx)) return; mx->flags |= SENTDEHALFOP; } if (plus == '+' && mode == 'h') { if (chan_senthalfop(mx) || chan_hashalfop(mx)) return; mx->flags |= SENTHALFOP; } if (plus == '-' && mode == 'v') { if (chan_sentdevoice(mx) || !chan_hasvoice(mx)) return; mx->flags |= SENTDEVOICE; } if (plus == '+' && mode == 'v') { if (chan_sentvoice(mx) || chan_hasvoice(mx)) return; mx->flags |= SENTVOICE; } } if (chan->compat == 0) { if (mode == 'e' || mode == 'I') chan->compat = 2; else chan->compat = 1; } else if (mode == 'e' || mode == 'I') { if (prevent_mixing && chan->compat == 1) flush_mode(chan, NORMAL); } else if (prevent_mixing && chan->compat == 2) flush_mode(chan, NORMAL); if (mode == 'o' || mode == 'h' || mode == 'b' || mode == 'v' || mode == 'e' || mode == 'I') { type = (plus == '+' ? PLUS : MINUS) | (mode == 'o' ? CHOP : (mode == 'h' ? CHHOP : (mode == 'b' ? BAN : (mode == 'v' ? VOICE : (mode == 'e' ? EXEMPT : INVITE))))); /* * FIXME: Some networks remove overlapped bans, * IRCnet does not (poptix/drummer) * * Note: On IRCnet ischanXXX() should be used, otherwise isXXXed(). */ if ((plus == '-' && ((mode == 'b' && !ischanban(chan, op)) || (mode == 'e' && !ischanexempt(chan, op)) || (mode == 'I' && !ischaninvite(chan, op)))) || (plus == '+' && ((mode == 'b' && ischanban(chan, op)) || (mode == 'e' && ischanexempt(chan, op)) || (mode == 'I' && ischaninvite(chan, op))))) return; /* If there are already max_bans bans, max_exempts exemptions, * max_invites invitations or max_modes +b/+e/+I modes on the * channel, don't try to add one more. */ if (plus == '+' && (mode == 'b' || mode == 'e' || mode == 'I')) { int bans = 0, exempts = 0, invites = 0; for (m = chan->channel.ban; m && m->mask[0]; m = m->next) bans++; if ((mode == 'b') && (bans >= max_bans)) return; for (m = chan->channel.exempt; m && m->mask[0]; m = m->next) exempts++; if ((mode == 'e') && (exempts >= max_exempts)) return; for (m = chan->channel.invite; m && m->mask[0]; m = m->next) invites++; if ((mode == 'I') && (invites >= max_invites)) return; if (bans + exempts + invites >= max_modes) return; } /* op-type mode change */ for (i = 0; i < modesperline; i++) if (chan->cmode[i].type == type && chan->cmode[i].op != NULL && !rfc_casecmp(chan->cmode[i].op, op)) return; /* Already in there :- duplicate */ l = strlen(op) + 1; if (chan->bytes + l > mode_buf_len) flush_mode(chan, NORMAL); for (i = 0; i < modesperline; i++) if (chan->cmode[i].type == 0) { chan->cmode[i].type = type; chan->cmode[i].op = (char *) channel_malloc(l); chan->bytes += l; /* Add 1 for safety */ strcpy(chan->cmode[i].op, op); break; } } /* +k ? store key */ else if (plus == '+' && mode == 'k') { if (chan->key) nfree(chan->key); chan->key = (char *) channel_malloc(strlen(op) + 1); if (chan->key) strcpy(chan->key, op); } /* -k ? store removed key */ else if (plus == '-' && mode == 'k') { if (chan->rmkey) nfree(chan->rmkey); chan->rmkey = (char *) channel_malloc(strlen(op) + 1); if (chan->rmkey) strcpy(chan->rmkey, op); } /* +l ? store limit */ else if (plus == '+' && mode == 'l') chan->limit = atoi(op); else { /* Typical mode changes */ if (plus == '+') strcpy(s, chan->pls); else strcpy(s, chan->mns); if (!strchr(s, mode)) { if (plus == '+') { chan->pls[strlen(chan->pls) + 1] = 0; chan->pls[strlen(chan->pls)] = mode; } else { chan->mns[strlen(chan->mns) + 1] = 0; chan->mns[strlen(chan->mns)] = mode; } } } modes = modesperline; /* Check for full buffer. */ for (i = 0; i < modesperline; i++) if (chan->cmode[i].type) modes--; if (include_lk && chan->limit) modes--; if (include_lk && chan->rmkey) modes--; if (include_lk && chan->key) modes--; if (modes < 1) flush_mode(chan, NORMAL); /* Full buffer! Flush modes. */ }
static void got_halfop(struct chanset_t *chan, char *nick, char *from, char *who, struct userrec *opu, struct flag_record *opper) { memberlist *m; char s[UHOSTLEN]; char ch[sizeof chan->name]; struct userrec *u; int check_chan = 0; int snm = chan->stopnethack_mode; m = ismember(chan, who); if (!m) { if (channel_pending(chan)) return; putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who); chan->status |= CHAN_PEND; refresh_who_chan(chan->name); return; } /* Did *I* just get halfopped? */ if (!me_op(chan) && !me_halfop(chan) && match_my_nick(who)) check_chan = 1; strcpy(ch, chan->name); simple_sprintf(s, "%s!%s", m->nick, m->userhost); if (!m->user) u = get_user_by_host(s); else u = m->user; get_user_flagrec(u, &victim, chan->dname); /* Flags need to be set correctly right from the beginning now, so that * add_mode() doesn't get irritated. */ m->flags |= CHANHALFOP; check_tcl_mode(nick, from, opu, chan->dname, "+h", who); if (!(chan = modebind_refresh(ch, from, opper, s, &victim)) || !(m = ismember(chan, who))) return; m->flags &= ~SENTHALFOP; if (channel_pending(chan)) return; if (nick[0] && HALFOP_CANDOMODE('h') && !match_my_nick(who) && !match_my_nick(nick)) { if (channel_bitch(chan) && !(glob_master(*opper) || glob_bot(*opper)) && !chan_master(*opper) && !(glob_halfop(victim) || glob_op(victim) || glob_bot(victim)) && !chan_op(victim) && !chan_halfop(victim)) add_mode(chan, '-', 'h', who); else if ((chan_dehalfop(victim) || (glob_dehalfop(victim) && !chan_halfop(victim))) && !glob_master(*opper) && !chan_master(*opper)) add_mode(chan, '-', 'h', who); else if (reversing) add_mode(chan, '-', 'h', who); } else if (reversing && HALFOP_CANDOMODE('h') && !match_my_nick(who) && !match_my_nick(nick)) add_mode(chan, '-', 'h', who); if (!nick[0] && HALFOP_CANDOMODE('h') && !match_my_nick(who)) { if (chan_dehalfop(victim) || (glob_dehalfop(victim) && !chan_halfop(victim))) { m->flags |= FAKEHALFOP; add_mode(chan, '-', 'h', who); } else if (snm > 0 && snm < 7 && !((channel_autohalfop(chan) || glob_autohalfop(victim) || chan_autohalfop(victim)) && (chan_halfop(victim) || (glob_halfop(victim) && !chan_dehalfop(victim)))) && !glob_exempt(victim) && !chan_exempt(victim)) { if (snm == 5) snm = channel_bitch(chan) ? 1 : 3; if (snm == 6) snm = channel_bitch(chan) ? 4 : 2; if (chan_washalfoptest(victim) || glob_washalfoptest(victim) || snm == 2) { if (!chan_washalfop(m)) { m->flags |= FAKEHALFOP; add_mode(chan, '-', 'h', who); } } else if (!(chan_halfop(victim) || (glob_halfop(victim) && !chan_dehalfop(victim)))) { if (snm == 1 || snm == 4 || (snm == 3 && !chan_washalfop(m))) { add_mode(chan, '-', 'h', who); m->flags |= FAKEHALFOP; } } else if (snm == 4 && !chan_washalfop(m)) { add_mode(chan, '-', 'h', who); m->flags |= FAKEHALFOP; } } } m->flags |= WASHALFOP; if (check_chan) recheck_channel(chan, 1); }
/* only to be used by test_set_one_attr */ static void set_one_attr_int(struct osd_device *osd, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number, uint64_t val) { struct osd_command cmd; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; uint8_t *data_out = NULL; uint64_t data_out_len; uint64_t attrval; int ret; struct attribute_list attr = { .type = ATTR_SET, .page = page, .number = number, .len = 8, .val = &attrval, }; set_htonll(&attrval, val); ret = osd_command_set_set_attributes(&cmd, pid, oid); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); } static void set_one_attr_val(struct osd_device *osd, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number, const void *val, uint16_t len) { struct osd_command cmd; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; uint8_t *data_out = NULL; uint64_t data_out_len; int ret,i; struct attribute_list attr = { .type = ATTR_SET, .page = page, .number = number, .len = len, .val = (void *)(uintptr_t) val, }; ret = osd_command_set_set_attributes(&cmd, pid, oid); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); /* output cdbfmt , length , value */ printf("cdbfmt is: %x \n", cmd.cdb[11]); printf("length is: %x \n", cmd.cdb[61]); printf("value is: "); for(i=0; i<=len; i++){ printf("%c", cmd.cdb[62+i]); } printf("\n"); } static void test_set_one_attr (struct osd_device *osd) { struct osd_command cmd; uint64_t pid = USEROBJECT_PID_LB; uint64_t oid = USEROBJECT_OID_LB; uint8_t *data_out = NULL; uint64_t data_out_len; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; int ret; uint32_t page = USEROBJECT_PG + LUN_PG_LB; /* create a partition*/ ret = osd_command_set_create_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* creat one object */ ret = osd_command_set_create(&cmd, USEROBJECT_PID_LB, USEROBJECT_OID_LB, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* these cases should not generate error */ set_one_attr_val(osd, pid, oid, page, 1, "test", 5); set_one_attr_val(osd, pid, oid, page, 1, "test_set_one_attr", 18); set_one_attr_int(osd, pid, oid, page, 1, 10); set_one_attr_int(osd, pid, oid, page, 1, 20); /* these cases must generate error */ /* set_one_attr_val(osd, pid, oid, page, 1, "ttest_set_one_attr", 19); */ /* set_one_attr_val(osd, pid, oid, page, 1, "", 0); */ } /* only to be used by test_osd_query */ static void set_attr_int(struct osd_device *osd, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number, uint64_t val) { struct osd_command cmd; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; uint8_t *data_out = NULL; uint64_t data_out_len; uint64_t attrval; int ret; struct attribute_list attr = { .type = ATTR_SET, .page = page, .number = number, .len = 8, .val = &attrval, }; set_htonll(&attrval, val); ret = osd_command_set_set_attributes(&cmd, pid, oid); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); } static void set_attr_val(struct osd_device *osd, uint64_t pid, uint64_t oid, uint32_t page, uint32_t number, const void *val, uint16_t len) { struct osd_command cmd; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; uint8_t *data_out = NULL; uint64_t data_out_len; int ret; struct attribute_list attr = { .type = ATTR_SET, .page = page, .number = number, .len = len, .val = (void *)(uintptr_t) val, }; ret = osd_command_set_set_attributes(&cmd, pid, oid); assert(ret == 0); ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); } static void set_qce(uint8_t *cp, uint32_t page, uint32_t number, uint16_t min_len, const void *min_val, uint16_t max_len, const void *max_val) { uint16_t len = 4 + 4 + 2 + min_len + 2 + max_len; set_htons(&cp[2], len); set_htonl(&cp[4], page); set_htonl(&cp[8], number); set_htons(&cp[12], min_len); memcpy(&cp[14], min_val, min_len); set_htons(&cp[14+min_len], max_len); memcpy(&cp[16+min_len], max_val, max_len); } static int ismember(uint64_t needle, uint64_t *hay, uint64_t haysz) { while (haysz--) if (needle == hay[haysz]) return 1; return 0; } static void check_results(uint8_t *matches, uint64_t matchlen, uint64_t *idlist, uint64_t idlistlen) { uint32_t add_len = get_ntohll(&matches[0]); assert(add_len == (5+8*idlistlen)); assert(matches[12] == (0x21 << 2)); assert(matchlen == add_len+8); add_len -= 5; matches += MIN_ML_LEN; while (add_len) { assert(ismember(get_ntohll(matches), idlist, 8)); matches += 8; add_len -= 8; } } void test_query(struct osd_device *osd) { struct osd_command cmd; uint64_t pid = PARTITION_PID_LB; uint64_t cid = COLLECTION_OID_LB; uint64_t oid = USEROBJECT_OID_LB + 1; /* leave room for cid */ uint8_t *data_out = NULL; uint64_t data_out_len; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; int i, ret; /* create a collection and stick some objects in it */ ret = osd_command_set_create_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); ret = osd_command_set_create_collection(&cmd, pid, cid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* but don't put all of the objects in the collection */ for (i=0; i<10; i++) { uint64_t attrval; struct attribute_list attr = { .type = ATTR_SET, .page = USER_COLL_PG, .number = 1, .len = 8, .val = &attrval, }; set_htonll(&attrval, cid); ret = osd_command_set_create(&cmd, pid, oid + i, 1); assert(ret == 0); if (!(i == 2 || i == 8)) { ret = osd_command_attr_build(&cmd, &attr, 1); assert(ret == 0); } ret = osdemu_cmd_submit(osd, cmd.cdb, cmd.outdata, cmd.outlen, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); osd_command_attr_free(&cmd); } /* * Set some random attributes for querying. */ uint32_t page = USEROBJECT_PG + LUN_PG_LB; set_attr_int(osd, pid, oid, page, 1, 4); set_attr_int(osd, pid, oid+1, page, 1, 49); set_attr_int(osd, pid, oid+1, page, 2, 130); set_attr_int(osd, pid, oid+2, page, 1, 20); set_attr_int(osd, pid, oid+3, page, 1, 101); set_attr_int(osd, pid, oid+4, page, 1, 59); set_attr_int(osd, pid, oid+4, page, 2, 37); set_attr_int(osd, pid, oid+5, page, 1, 75); set_attr_int(osd, pid, oid+6, page, 1, 200); set_attr_int(osd, pid, oid+7, page, 1, 67); set_attr_int(osd, pid, oid+8, page, 1, 323); set_attr_int(osd, pid, oid+8, page, 2, 44); set_attr_int(osd, pid, oid+9, page, 1, 1); set_attr_int(osd, pid, oid+9, page, 2, 19); /* * Various queries. */ /* run without query criteria */ uint8_t buf[1024], *cp, *matches; uint32_t qll; uint64_t matchlen; uint64_t idlist[8]; qll = MINQLISTLEN; memset(buf, 0, 1024); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid; idlist[1] = oid+1; idlist[2] = oid+3; idlist[3] = oid+4; idlist[4] = oid+5; idlist[5] = oid+6; idlist[6] = oid+7; idlist[7] = oid+9; check_results(matches, matchlen, idlist, 8); free(matches); matches = NULL; matchlen = 0; /* run one query without min/max constraints */ qll = 0; memset(buf, 0, 1024); cp = buf; set_qce(&cp[4], page, 2, 0, NULL, 0, NULL); qll += 4 + (4+4+4+2+2); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+1; idlist[1] = oid+4; idlist[2] = oid+9; check_results(matches, matchlen, idlist, 3); free(matches); matches = NULL; matchlen = 0; /* run one query with criteria */ uint64_t min, max; qll = 0; min = 40, max= 80; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x0; set_qce(&cp[4], page, 1, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+1; idlist[1] = oid+4; idlist[2] = oid+5; idlist[3] = oid+7; check_results(matches, matchlen, idlist, 4); free(matches); matches = NULL; matchlen = 0; /* run union of two query criteria */ qll = 0; /* first query */ min = 100, max = 180; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x0; /* UNION */ set_qce(&cp[4], page, 1, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); /* second query */ min = 200, max = 323; set_htonll(&min, min); set_htonll(&max, max); set_qce(cp, page, 1, sizeof(min), &min, sizeof(max), &max); qll += (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += (4+4+4+2+sizeof(min)+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+3; idlist[1] = oid+6; check_results(matches, matchlen, idlist, 2); free(matches); matches = NULL; matchlen = 0; /* run intersection of 2 query criteria */ qll = 0; /* first query */ min = 4, max = 100; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x1; /* INTERSECTION */ set_qce(&cp[4], page, 1, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); /* second query */ min = 10, max = 400; set_htonll(&min, min); set_htonll(&max, max); set_qce(cp, page, 2, sizeof(min), &min, sizeof(max), &max); qll += (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += (4+4+4+2+sizeof(min)+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+1; idlist[1] = oid+4; check_results(matches, matchlen, idlist, 2); free(matches); matches = NULL; matchlen = 0; /* run union of 3 query criteria, with missing min/max */ qll = 0; /* first query */ min = 130, max = 130; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x0; /* UNION */ set_qce(&cp[4], page, 2, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); /* second query */ min = 150; set_htonll(&min, min); set_qce(cp, page, 1, sizeof(min), &min, 0, NULL); qll += (4+4+4+2+sizeof(min)+2+0); cp += (4+4+4+2+sizeof(min)+2+0); /* third query */ max = 10; set_htonll(&max, max); set_qce(cp, page, 1, 0, NULL, sizeof(max), &max); qll += (4+4+4+2+0+2+sizeof(max)); cp += (4+4+4+2+0+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[3] = oid; idlist[4] = oid+1; idlist[5] = oid+6; idlist[2] = oid+9; check_results(matches, matchlen, idlist, 4); free(matches); matches = NULL; matchlen = 0; /* set some attributes with text values */ set_attr_val(osd, pid, oid, page, 1, "hello", 6); set_attr_val(osd, pid, oid+1, page, 1, "cat", 4); set_attr_int(osd, pid, oid+1, page, 2, 130); set_attr_int(osd, pid, oid+2, page, 1, 20); set_attr_val(osd, pid, oid+3, page, 1, "zebra", 6); set_attr_int(osd, pid, oid+4, page, 1, 59); set_attr_int(osd, pid, oid+4, page, 2, 37); set_attr_int(osd, pid, oid+5, page, 1, 75); set_attr_val(osd, pid, oid+6, page, 1, "keema", 6); set_attr_int(osd, pid, oid+7, page, 1, 67); set_attr_int(osd, pid, oid+8, page, 1, 323); set_attr_int(osd, pid, oid+8, page, 2, 44); set_attr_int(osd, pid, oid+9, page, 1, 1); set_attr_val(osd, pid, oid+9, page, 2, "hotelling", 10); /* run queries on different datatypes, with diff min max lengths */ qll = 0; /* first query */ min = 41, max = 169; set_htonll(&min, min); set_htonll(&max, max); memset(buf, 0, 1024); cp = buf; cp[0] = 0x0; /* UNION */ set_qce(&cp[4], page, 1, sizeof(min), &min, sizeof(max), &max); qll += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += 4 + (4+4+4+2+sizeof(min)+2+sizeof(max)); /* second query */ set_qce(cp, page, 1, 3, "ab", 5, "keta"); qll += (4+4+4+2+2+2+5); cp += (4+4+4+2+2+2+5); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[3] = oid; idlist[4] = oid+1; idlist[0] = oid+4; idlist[1] = oid+5; idlist[5] = oid+6; idlist[2] = oid+7; check_results(matches, matchlen, idlist, 6); free(matches); matches = NULL; matchlen = 0; /* run intersection of 3 query criteria, with missing min/max */ qll = 0; /* first query */ memset(buf, 0, 1024); cp = buf; cp[0] = 0x1; /* INTERSECTION */ set_qce(&cp[4], page, 1, 2, "a", 3, "zz"); qll += 4 + (4+4+4+2+2+2+3); cp += 4 + (4+4+4+2+2+2+3); /* second query */ min = 140; set_htonll(&min, min); set_qce(cp, page, 1, sizeof(min), &min, 0, NULL); qll += (4+4+4+2+sizeof(min)+2+0); cp += (4+4+4+2+sizeof(min)+2+0); /* third query */ set_qce(cp, page, 2, 0, NULL, 6, "alpha"); qll += (4+4+4+2+0+2+6); cp += (4+4+4+2+0+2+6); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); idlist[0] = oid+1; check_results(matches, matchlen, idlist, 1); free(matches); matches = NULL; matchlen = 0; /* run intersection of 2 query criteria with empty result */ qll = 0; /* first query */ memset(buf, 0, 1024); cp = buf; cp[0] = 0x1; /* INTERSECTION */ set_qce(&cp[4], page, 1, 3, "aa", 4, "zzz"); qll += 4 + (4+4+4+2+3+2+4); cp += 4 + (4+4+4+2+3+2+4); /* second query */ min = 50; max = 80; set_htonll(&min, min); set_htonll(&max, max); set_qce(cp, page, 1, sizeof(min), &min, sizeof(max), &max); qll += (4+4+4+2+sizeof(min)+2+sizeof(max)); cp += (4+4+4+2+sizeof(min)+2+sizeof(max)); ret = osd_command_set_query(&cmd, pid, cid, qll, 4096); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, buf, qll, &matches, &matchlen, sense_out, &senselen_out); assert(ret == 0); check_results(matches, matchlen, idlist, 0); free(matches); matches = NULL; matchlen = 0; /* * Cleanup. */ for (i=0; i<10; i++) { ret = osd_command_set_remove(&cmd, pid, oid + i); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } ret = osd_command_set_remove_collection(&cmd, pid, cid, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); ret = osd_command_set_remove_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } struct test_attr { uint8_t type; uint64_t oid; uint32_t page; uint32_t number; uint64_t intval; uint16_t valen; const void *val; }; static void ismember_attr(struct test_attr *attr, size_t sz, uint64_t oid, uint32_t page, uint32_t number, uint64_t valen, const void *val) { size_t i = 0; for (i = 0; i < sz; i++) { if (attr[i].oid == oid && attr[i].page == page && attr[i].number == number) { assert(valen <= attr[i].valen); if (attr[i].type == 1) { if (valen == attr[i].valen) assert(attr[i].intval == get_ntohll(val)); } else { assert(memcmp(attr[i].val, val, valen) == 0); } return; } } fprintf(stderr, "unknown attr: oid: %llu, page %u, number %u\n", llu(oid), page, number); assert(0); /* unknown attr */ } static void test_oids_with_attr(struct osd_device *osd, uint64_t pid, struct attribute_list *getattr, int numattr, uint64_t alloc_len, uint64_t exp_data_out_len, uint64_t exp_add_len, uint64_t exp_cont_id, uint8_t exp_odf, struct test_attr *attrs, size_t attrs_sz) { int ret = 0; struct osd_command cmd; uint8_t *cp = NULL; uint32_t page = 0, number = 0; uint64_t data_in_len, data_out_len; const void *data_in; uint8_t *data_out = NULL; uint64_t oid = 0; uint8_t sense_out[OSD_MAX_SENSE]; uint16_t len = 0; int senselen_out; uint32_t attr_list_len = 0; /* execute list with attr, alloc length less than required */ ret = osd_command_set_list(&cmd, pid, 0, alloc_len, 0, 1); assert(ret == 0); ret = osd_command_attr_build(&cmd, getattr, numattr); assert(ret == 0); data_in = cmd.outdata; data_in_len = cmd.outlen; ret = osdemu_cmd_submit(osd, cmd.cdb, data_in, data_in_len, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); cp = data_out; assert(data_out_len == exp_data_out_len); assert(get_ntohll(cp) == exp_add_len); cp += 8; assert(get_ntohll(cp) == exp_cont_id); cp += 8; assert(get_ntohl(cp) == 0); cp += 7; assert(cp[0] == exp_odf); cp += 1; oid = 0; attr_list_len = 0; len = 0; data_out_len -= 24; while (data_out_len > 0) { oid = get_ntohll(cp); cp += 12; attr_list_len = get_ntohl(cp); cp += 4; data_out_len -= 16; while (attr_list_len > 0) { page = get_ntohl(cp); cp += 4; number = get_ntohl(cp); cp += 4; len = get_ntohs(cp); cp += 2; attr_list_len -= (4+4+2); data_out_len -= (4+4+2); if (len > attr_list_len) { len = attr_list_len; } ismember_attr(attrs, attrs_sz, oid, page, number, len, cp); cp += len; cp += (roundup8(2+len) - (2+len)); data_out_len -= len; data_out_len -= (roundup8(2+len) - (2+len)); attr_list_len -= len; attr_list_len -= (roundup8(2+len) - (2+len)); } } free(data_out); data_out = NULL; osd_command_attr_free(&cmd); } void test_list(struct osd_device *osd) { struct osd_command cmd; uint64_t pid = PARTITION_PID_LB; uint64_t cid = 0; uint64_t oid = 0; uint8_t *data_out = NULL; uint8_t *cp; uint32_t page = 0, number = 0; uint64_t data_out_len; uint64_t idlist[64]; uint8_t sense_out[OSD_MAX_SENSE]; int senselen_out; int i, ret; /* create partition */ ret = osd_command_set_create_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create collection */ ret = osd_command_set_create_collection(&cmd, pid, cid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create 6 objects */ ret = osd_command_set_create(&cmd, pid, 0, 6); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create another collection */ ret = osd_command_set_create_collection(&cmd, pid, cid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* create 4 objects */ ret = osd_command_set_create(&cmd, pid, 0, 4); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); /* set attributes on userobjects */ page = USEROBJECT_PG + LUN_PG_LB; number = 1; oid = COLLECTION_OID_LB + 1; struct test_attr attrs[] = { {1, oid, page, number, 1, 8, NULL}, {1, oid, page+1, number+1, 768, 8, NULL}, {2, oid, page+2, number+2, 0, 5, "sudo"}, {1, oid+1, page+1, number+1, 56, 8, NULL}, {1, oid+1, page+2, number+2, 68, 8, NULL}, {2, oid+2, page+2, number+2, 0, 9, "deadbeef"}, {1, oid+3, page+3, number+3, 1, 8, NULL}, {1, oid+3, page+1, number+1, 111, 8, NULL}, {2, oid+3, page+4, number+4, 0, 5, "sudo"}, {1, oid+3, page+2, number+2, 11, 8, NULL}, {1, oid+3, page+5, number+5, 111111, 8, NULL}, {2, oid+4, page+4, number+4, 0, 6, "milli"}, {2, oid+4, page+5, number+5, 0, 10, "kilometer"}, {2, oid+4, page+3, number+3, 0, 11, "hectameter"}, {2, oid+5, page+1, number+1, 0, 12, "zzzzzzhhhhh"}, {2, oid+5, page+2, number+2, 0, 2, "b"}, {1, oid+5, page+3, number+3, 6, 8, NULL}, {1, oid+7, page+1, number+1, 486, 8, NULL}, {1, oid+7, page+4, number+4, 586, 8, NULL}, {1, oid+7, page+2, number+2, 686, 8, NULL}, {1, oid+8, page, number, 4, 8, NULL}, {2, oid+9, page+1, number+1, 0, 14, "setting these"}, {2, oid+9, page+2, number+2, 0, 11, "attributes"}, {2, oid+9, page+3, number+3, 0, 8, "made me"}, {2, oid+9, page+4, number+4, 0, 12, "mad! really"}, {1, oid+10, page+1, number+1, 1234567890, 8, NULL}, {2, oid+10, page, number, 0, 6, "DelTa"}, }; for (i = 0; i < ARRAY_SIZE(attrs); i++) { if (attrs[i].type == 1) { set_attr_int(osd, pid, attrs[i].oid, attrs[i].page, attrs[i].number, attrs[i].intval); } else { set_attr_val(osd, pid, attrs[i].oid, attrs[i].page, attrs[i].number, attrs[i].val, attrs[i].valen); } } /* set some attributes on collections */ page = COLLECTION_PG + LUN_PG_LB; cid = COLLECTION_OID_LB; set_attr_int(osd, pid, cid, page, 1, 1); set_attr_int(osd, pid, cid+7, page, 2, 2); /* execute list command. get only oids first */ ret = osd_command_set_list(&cmd, pid, 0, 4096, 0, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); cp = data_out; assert(get_ntohll(cp) == 10*8+16); assert(data_out_len == 10*8+24); cp += 8; assert(get_ntohll(cp) == 0); cp += 8; assert(get_ntohl(cp) == 0); cp += 7; assert(cp[0] == (0x21 << 2)); cp += 1; data_out_len -= 24; oid = COLLECTION_OID_LB + 1; for (i = 0; i < 6; i++) idlist[i] = oid + i; oid = COLLECTION_OID_LB + 1 + i + 1; for (i = 0; i < 4; i++) idlist[6+i] = oid + i; while (data_out_len > 0) { assert(ismember(get_ntohll(cp), idlist, 10)); cp += 8; data_out_len -= 8; } free(data_out); data_out = NULL; osd_command_attr_free(&cmd); /* execute list command with less space */ ret = osd_command_set_list(&cmd, pid, 0, 72, 0, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); cp = data_out; assert(get_ntohll(cp) == 10*8+16); assert(data_out_len == 72); cp += 8; assert(get_ntohll(cp) == COLLECTION_OID_LB + 8); cp += 8; assert(get_ntohl(cp) == 0); cp += 7; assert(cp[0] == (0x21 << 2)); cp += 1; data_out_len -= 24; oid = COLLECTION_OID_LB + 1; for (i = 0; i < 6; i++) idlist[i] = oid + i; for (i = 0; i < 4; i++) idlist[6+i] = 0; while (data_out_len > 0) { assert(ismember(get_ntohll(cp), idlist, 10)); cp += 8; data_out_len -= 8; } free(data_out); data_out = NULL; osd_command_attr_free(&cmd); page = USEROBJECT_PG + LUN_PG_LB; number = 1; struct attribute_list getattr[] = { {ATTR_GET, page, number, NULL, 0, 0}, {ATTR_GET, page+1, number+1, NULL, 0, 0}, {ATTR_GET, page+2, number+2, NULL, 0, 0}, {ATTR_GET, page+3, number+3, NULL, 0, 0}, {ATTR_GET, page+4, number+4, NULL, 0, 0}, {ATTR_GET, page+5, number+5, NULL, 0, 0}, }; /* execute list with attr */ test_oids_with_attr(osd, pid, getattr, 6, 4096, 792, 784, 0, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 200, 200, 784, 65539, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 208, 208, 784, 65539, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 216, 208, 784, 65539, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 544, 536, 784, 65544, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 688, 688, 784, 65546, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* execute list with attr, alloc length less than required */ test_oids_with_attr(osd, pid, getattr, 6, 680, 680, 784, 65546, (0x22 << 2), attrs, ARRAY_SIZE(attrs)); /* clean up */ oid = USEROBJECT_OID_LB; for (i=0; i<12; i++) { if (i == 0 || i == 7) continue; ret = osd_command_set_remove(&cmd, pid, oid + i); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } cid = COLLECTION_OID_LB; ret = osd_command_set_remove_collection(&cmd, pid, cid, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); cid = COLLECTION_OID_LB + 7; ret = osd_command_set_remove_collection(&cmd, pid, cid, 0); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); ret = osd_command_set_remove_partition(&cmd, pid); assert(ret == 0); ret = osdemu_cmd_submit(osd, cmd.cdb, NULL, 0, &data_out, &data_out_len, sense_out, &senselen_out); assert(ret == 0); } static void test_attr_vals(uint8_t *cp, struct attribute_list *attrs, size_t sz) { size_t i = 0; uint32_t page = 0; uint32_t num = 0; uint16_t len = 0; uint32_t list_len = 0; assert((cp[0] & 0x0F) == 0x9); cp += 4; list_len = get_ntohl(cp); cp += 4; while (list_len > 0) { page = get_ntohl(cp); cp += 4; num = get_ntohl(cp); cp += 4; len = get_ntohs(cp); cp += 2; for (i = 0; i < sz; i++) { if (!(attrs[i].page==page && attrs[i].number==num)) continue; assert(len == attrs[i].len); if (len == 8) { assert(get_ntohll(attrs[i].val) == get_ntohll(cp)); } else if (len != 0) { assert(memcmp(attrs[i].val, cp, len) == 0); } break; } assert(i < sz); if (len == 0) { cp += (roundup8(10) - 10); list_len -= roundup8(4+4+2); } else { cp += len; cp += (roundup8(2+len) - (2+len)); list_len -= roundup8(4+4+2+len); } } assert(list_len == 0); }
static void got_dehalfop(struct chanset_t *chan, char *nick, char *from, char *who, struct userrec *opu) { memberlist *m; char ch[sizeof chan->name]; char s[UHOSTLEN], s1[UHOSTLEN]; struct userrec *u; int had_halfop; m = ismember(chan, who); if (!m) { if (channel_pending(chan)) return; putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who); chan->status |= CHAN_PEND; refresh_who_chan(chan->name); return; } strcpy(ch, chan->name); simple_sprintf(s, "%s!%s", m->nick, m->userhost); simple_sprintf(s1, "%s!%s", nick, from); u = get_user_by_host(s); get_user_flagrec(u, &victim, chan->dname); had_halfop = chan_hasop(m); /* Flags need to be set correctly right from the beginning now, so that * add_mode() doesn't get irritated. */ m->flags &= ~(CHANHALFOP | SENTDEHALFOP | FAKEHALFOP); check_tcl_mode(nick, from, opu, chan->dname, "-h", who); if (!(chan = modebind_refresh(ch, from, &user, s, &victim)) || !(m = ismember(chan, who))) return; /* Check comments in got_op() (drummer) */ m->flags &= ~WASHALFOP; if (channel_pending(chan)) return; /* Dehalfop'd someone on my oplist? */ if (HALFOP_CANDOMODE('h')) { int ok = 1; if (!glob_dehalfop(victim) && !chan_dehalfop(victim)) { if (channel_protecthalfops(chan) && (glob_master(victim) || chan_master(victim) || glob_halfop(victim) || chan_halfop(victim))) ok = 0; else if (channel_protectfriends(chan) && (glob_friend(victim) || chan_friend(victim))) ok = 0; } if ((reversing || !ok) && had_halfop && !match_my_nick(nick) && rfc_casecmp(who, nick) && !match_my_nick(who) && !glob_master(user) && !chan_master(user) && !glob_bot(user) && ((chan_halfop(victim) || (glob_halfop(victim) && !chan_dehalfop(victim))) || !channel_bitch(chan))) add_mode(chan, '+', 'h', who); } if (!nick[0]) putlog(LOG_MODES, chan->dname, "TS resync (%s): %s deopped by %s", chan->dname, who, from); if (!(m->flags & (CHANVOICE | STOPWHO))) { chan->status |= CHAN_PEND; refresh_who_chan(chan->name); m->flags |= STOPWHO; } }
static void got_deop(struct chanset_t *chan, char *nick, char *from, char *who, struct userrec *opu) { memberlist *m; char ch[sizeof chan->name]; char s[UHOSTLEN], s1[UHOSTLEN]; struct userrec *u; int had_halfop; m = ismember(chan, who); if (!m) { if (channel_pending(chan)) return; putlog(LOG_MISC, chan->dname, CHAN_BADCHANMODE, chan->dname, who); chan->status |= CHAN_PEND; refresh_who_chan(chan->name); return; } strcpy(ch, chan->name); simple_sprintf(s, "%s!%s", m->nick, m->userhost); simple_sprintf(s1, "%s!%s", nick, from); u = get_user_by_host(s); get_user_flagrec(u, &victim, chan->dname); had_halfop = chan_hasop(m); /* Flags need to be set correctly right from the beginning now, so that * add_mode() doesn't get irritated. */ m->flags &= ~(CHANOP | SENTDEOP | FAKEOP); check_tcl_mode(nick, from, opu, chan->dname, "-o", who); if (!(chan = modebind_refresh(ch, from, &user, s, &victim)) || !(m = ismember(chan, who))) return; m->flags &= ~WASOP; if (channel_pending(chan)) return; if (HALFOP_CANDOMODE('o')) { int ok = 1; if (!glob_deop(victim) && !chan_deop(victim)) { if (channel_protectops(chan) && (glob_master(victim) || chan_master(victim) || glob_op(victim) || chan_op(victim))) ok = 0; else if (channel_protectfriends(chan) && (glob_friend(victim) || chan_friend(victim))) ok = 0; } if ((reversing || !ok) && had_halfop && !match_my_nick(nick) && rfc_casecmp(who, nick) && !match_my_nick(who) && !glob_master(user) && !chan_master(user) && !glob_bot(user) && ((chan_op(victim) || (glob_op(victim) && !chan_deop(victim))) || !channel_bitch(chan))) add_mode(chan, '+', 'o', who); } if (!nick[0]) putlog(LOG_MODES, chan->dname, "TS resync (%s): %s deopped by %s", chan->dname, who, from); /* Check for mass deop */ if (nick[0]) detect_chan_flood(nick, from, s1, chan, FLOOD_DEOP, who, 0); /* Having op hides your +v and +h status -- so now that someone's lost ops, * check to see if they have +v or +h */ if (!(m->flags & (CHANVOICE | CHANHALFOP | STOPWHO))) { chan->status |= CHAN_PEND; refresh_who_chan(chan->name); m->flags |= STOPWHO; } /* Was the bot deopped? */ if (match_my_nick(who)) { /* Cancel any pending kicks and modes */ memberlist *m2; for (m2 = chan->channel.member; m2 && m2->nick[0]; m2 = m2->next) m2->flags &= ~(SENTKICK | SENTDEOP | SENTOP | SENTVOICE | SENTDEVOICE); check_tcl_need(chan->dname, "op"); if (chan->need_op[0]) do_tcl("need-op", chan->need_op); if (!nick[0]) putlog(LOG_MODES, chan->dname, "TS resync deopped me on %s :(", chan->dname); } if (nick[0]) maybe_revenge(chan, s1, s, REVENGE_DEOP); }