Before this commit, the plugin first fetched a list of all
(deserialized) records in a list, then reversed the list, and iterated
on the reverse list.
This proved to be slow, with most of the time being spent in
`dbi.DB._newRecord` (which essentially deserializes one list of CSV).
After this commit, the list is reversed first, then the plugin iterates
on its generator, which calls `_newRecord` on records as they are
requested.
This means that when there are many URLs in the database, `@last` does
not need to waste time deserializing most records, when the result is
near the end (and if the result is the first record, then it does
exactly as much work as before).
With some locale configurations (not that uncommon on CentOS), open() may
default to non-UTF8 encodings (eg. ANSI_X3.4-1968).
This is usually not an issue, because we use open() both for writing and
reading. However, AtomicFile implicitly enforces UTF8; which needs to be
mirrored when reading.
Otherwise, normalization is useless, and gives a surprising error message,
such as:
```
<user> config plugins.rss.sortfeeditems oldestfirst
<bot> Error: Valid values include 'asInFeed', 'oldestFirst', 'newestFirst', 'outdatedFirst', and 'updatedFirst', not 'oldestFirst'.
```
This is consistent with what we already do with commands; and generally
makes sense, as we don't want to re-send titles and others when cycling
on UnrealIRCd (which includes a chathistory batch when joining when
chmode +H is set, despite umode +B)
The previous heuristic runs into false positives when imports are merged in __init__.py
More broadly though, it's unlikely automatic 2to3 is particularly useful in 2022 - plugins that were written ~10 years ago are unlikely to work even if syntax errors are fixed.
Spawning one process for each message was a little silly, considering
there can be thousands of messages.
Plus, some instances do reach the timeout after running for a few weeks,
so we really need to fix this.
Ideally, `regexp_wrapper` should also be removed from other plugins
(Todo, Notes, ...) as they have the same issues, but this will do for
now.
.getSpecific() always returned the channel-specific but non-network-specific var,
unless the channel-specific and network-specific one was manually set.