This shows you the differences between two versions of the page.
— |
list_identifiers [2011/10/17 23:51] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== Identifier behaviour in various types of lists ====== | ||
+ | //Author// --- //[[nousername@gmx.net|qwerty]] 2006/09/16 14:45// | ||
+ | mIRC has five types of lists that accept address-mask entries: one is the Users list, found in mIRC Editor's //Users// tab. The other four are those found in the Control section of mIRC's address book: Ignore, Op, Voice and Protect. | ||
+ | |||
+ | For each of these lists, there are one or more identifiers that allow you to compare a user's address against the list and determine if there's a match. However, these identifiers do not behave the same way. The purpose of this article to delineate those differences. | ||
+ | |||
+ | For the Users list, we have two identifiers, $level() and $ulist(). Let's start with $level; the help file says that $level() searches the Users list for the specified address and the example uses an address mask of type 2 (for more on masks see /help $mask). So if your Users list looks something like this: | ||
+ | <file>10:qwerty!*@foo.com | ||
+ | 15:*!test@*.com | ||
+ | 42:*!*@blah.com</file> | ||
+ | then typing <code>//echo -a $level(*!*@blah.com)</code> will give you //42//; mIRC searched through the Users list for the exact entry //*!*@blah.com// and found it. However, $level() also accepts full addresses (of the form nick!address@host), which is what makes it really useful. When you specify a full address, mIRC goes through the list and compares each item against the specified full address; if the current item is a wildcard string that matches the full address, the associated level is returned. Think of it as an internal sort of <code>if (<list item> iswm <full address>)</code>So <code>//echo -a $level(somenick!someuser@blah.com)</code> gives //42//. | ||
+ | |||
+ | The other identifier, $ulist() is more powerful though; not only does it accept either an exact mask or a full address, like $level(), but it also accepts wildcard address masks that are not in the Users list. Considering the above Users list, typing <code>//echo -a $ulist(bleh!*@something.com)</code> gives you //*!test@*.com//. Why? Because when mIRC goes through the list, it performs two checks for each item: it checks whether the current list entry is a wildcard string that matches the specified address (or address mask) but it also checks for the opposite, that is whether the specified address mask is a wildcard string that matches the list entry. A scripting equivalent of what's going on would be<code>if ((<current item> iswm <address>) || (<address> iswm <current item>))</code> | ||
+ | |||
+ | Now about the other list types. For the Ignore list, we have the $ignore() identifier. This one works exactly like $level(): it either looks for an exact match in the ignore list or it checks whether each item in the list is a wildcard string that matches the specified full address. This means that if you add //qwerty!*@foo.com// in your ignore list, both <code>//echo -a $ignore(qwerty!user@foo.com)</code> and <code>//echo -a $ignore(qwerty!*@foo.com)</code> will give you back //qwerty!*@foo.com//, however <code>//echo -a $ignore(qwerty!*test*@foo.com)</code> will give you an //insufficient parameters// error (meaning $ignore() returned $null). | ||
+ | |||
+ | The Auto-Op and Auto-Voice list identifiers $aop() and $avoice() have identical behaviour, which matches $ulist()'s behaviour; they perform the same "2-way" comparison, thus they are more powerful than $ignore(). | ||
+ | |||
+ | The Protect list identifier $protect(), however, seems to be broken in mIRC v6.2; it only accepts an exact mask, that is a mask that's represented literally in the Protect list. So if your Protect list contains //*!*@blah.com//, only $protect(*!*@blah.com) returns that entry; both $protect(foo!bar@blah.com) and $protect(*!bar@blah.com) return $null. | ||
+ | |||
+ | **NOTE:** the exact same rules that apply to address book identifiers also aply to their respective /if operators. That is, //isignore, isaop, isavoice, isprotect// exhibit identical behaviour to //$ignore(), $aop(), $avoice(), $protect()// respectively. | ||
+ | |||
+ | ===== Discussion ===== | ||
+ | |||
+ | While performing some additional tests, I got the following results.. ('isban' included just because it also takes masks) | ||
+ | |||
+ | ^ ^ nick ^ full ^ narrow ^ exact ^ wide ^ all ^ | ||
+ | | $aop | | x | x | x | | | | ||
+ | | isaop | | x | x | x | | | | ||
+ | | $avoice | | x | x | x | | | | ||
+ | | isavoice | | x | x | x | | | | ||
+ | | $ignore | | x | | x | | | | ||
+ | | isignore | | x | | x | | | | ||
+ | | $protect | x | | | x | | | | ||
+ | | isprotect | x | | | x | | | | ||
+ | | $level | | x | x | x | | | | ||
+ | | $ulist | | x | x | x | x | | | ||
+ | | isban | | x | | x | | | | ||
+ | |||
+ | The entry assumed present in all lists is *!*@host.domain. Legend: | ||
+ | |||
+ | ^ entry ^ mask tested ^ description ^ | ||
+ | | nick | nick | nickname of matching person currently in IAL | | ||
+ | | full | nick!user@host.domain | full address, no wildcards | | ||
+ | | narrow | *!user@host.domain | narrower wildcard mask | | ||
+ | | exact | *!*@host.domain | exact address as present in list | | ||
+ | | wide | *!*@*.domain | wilder wildcard mask | | ||
+ | | all | *!*@* | mask matching every possible mask | | ||
+ | |||
+ | Clearly $protect/isprotect are different from the rest, but the rest on itself is also far from consistent! Especially $ulist is worth a closer look though, as a few more tests of the "*!user@* vs *!*@*.domain" kind yielded all sorts of seemingly illogical results. With a large number of test cases, I've tried to procedurize how $ulist decides whether there is a match between the given input address and an entry in the userlist. | ||
+ | |||
+ | In comparison, for **$level** this process is rather straightforward. It can be assumed that $level iterates through the userlist, entry by entry, and tries to decide for each whether there is a match - that is, for each entry in the userlist, it checks this userlist <entry> against the <input> as given as first parameter and decides between match/no match. A very close approximation of this matching process can be described as follows: | ||
+ | |||
+ | - If the userlist entry <entry> is a basic nickname, meaning the entry does not contain any of the following characters: '!', '@', '*', '?', then it is implicitly considered to be suffixed with '!*', effectively turning "<entry>" into "<entry>!*" for the next step. | ||
+ | - A match is assumed if, and only if, the userlist entry is a wildcard-match against the given input: "<entry> iswm <input>". | ||
+ | |||
+ | This indeed fully explains the full/narrow/exact data points in the table above, as well as pretty much all other combinations I could come up with.((The only errors were on the diagonal of my test matrix, indicating some malformed (i.e. not wildcarded nick!user@host format) entries would behave differently than expected when matched against themselves.)) | ||
+ | |||
+ | However, **$ulist** is much more complicated than that! Even if we ignore the L and N parameters and again fully concentrate on the most basic yes/no test whether <entry> in the userlist is a match for the given <input>, there are lots of strange things about $ulist. The simplest procedurization of $ulist's matching algorithm that I could come up with, is the following: | ||
+ | |||
+ | - If the given input is exactly a single star "*", it's a match. | ||
+ | - The given input <input> is extended to form an (optionally) wildcarded nick!user@host format, according to the rules given below. | ||
+ | - Like with $level, <entry> is suffixed with "!*" if it does not contain any of the characters '!@*?'. | ||
+ | - If <entry> is a wildcard match against <input> ("<entry> iswm <input>"), it's a match. | ||
+ | - If <entry> contains no wildcards, and <input> is a wildcard match against <entry> ("<input> iswm <entry>"), it's a match. | ||
+ | - If <entry> can not be split up in a <entry-nick>, <entry-user> and <entry-host> portion, it's not a match. <input> is split up in the same way at this point, but this can never fail because of the extension earlier. | ||
+ | - If either <entry-host> or <input-host> (or both) are a single wildcard, i.e. either the userlist entry or the extended input ended with "@*", then it's not a match. | ||
+ | - Now each of the three pairs <entry-nick> and <input-nick>, <entry-user> and <input-user>, <entry-host> and <input-host>, are checked with a two-way wildcard matching algorithm (see below). At this point, a match is assumed if, and only if, all three pairs are two-way wildcard matches. | ||
+ | |||
+ | This indeed seems overly and unnecessarily complex, but I do not see a way to reduce the number of steps of this procedurization while yielding the same results - I've tested this procedurization as well and it seems to always yield the same results as $ulist itself.((Again, except for some errors on the diagonal with malformed entries.)) $ulist's **input extension** is as follows: | ||
+ | |||
+ | * If the input contains neither a '!' or a '@', add '!*@*' at the end. | ||
+ | * Otherwise, if the input contains no '!', insert '*!' at the beginning. | ||
+ | * Otherwise, if the input contains no '@', add '@*' at the end. | ||
+ | |||
+ | The **two-way wildcard matching** algorithm is a little too messy to describe here in full detail, but essentially it takes two wildcard strings as input, and decides whether there could //potentially// be a literal text string that is matched by both wildcard strings. For example, *a* and *b* match; a* and *b match; a* and b* don't. Wildcards '*' and '?' are both supported. | ||
+ | |||
+ | Again, I have no idea why $ulist is so incredibly complicated. Its behaviour doesn't strike me as particularly useful.. --- //[[saturn@xise.nl|Saturn]] 2006/09/25 20:54// |