| 1 |
3.1.4: 2010-xx-xx |
| 2 |
|
| 3 |
IMAP QUOTA works. |
| 4 |
|
| 5 |
Smarthost SIZE is forwarded to SMTP submit clients. |
| 6 |
|
| 7 |
Several bugs and one missing feature: |
| 8 |
|
| 9 |
1. INTHREAD doesn't work now. Not sure why. |
| 10 |
|
| 11 |
2. INTHREAD OLDER and similar searches don't work; the date-based |
| 12 |
searches look at the outer message. |
| 13 |
|
| 14 |
3. THREAD needs retesting. It may be broken. |
| 15 |
|
| 16 |
4. COMPRESS now reimplemented, and may work better with iphone 4. |
| 17 |
|
| 18 |
IMAP::emitResponses still needs a tweak or two. |
| 19 |
|
| 20 |
And the feature: automatic flag-based views. Almost everything is |
| 21 |
ready. |
| 22 |
|
| 23 |
SORT(SUBJECT) is broken. The only way to fix it is to add a postgres |
| 24 |
function to implement the moronic baseness algorithm in the RFC. I can't |
| 25 |
write that sort of thing. |
| 26 |
|
| 27 |
|
| 28 |
SEARCH=ADDRESS |
| 29 |
|
| 30 |
Hack roundcube to use S=A, S=I and blah in order to present |
| 31 |
gmail-like a thread/address view. |
| 32 |
|
| 33 |
|
| 34 |
HelperRowCreator |
| 35 |
|
| 36 |
If that were to use a Cache, message injection would be speeded up |
| 37 |
significantly. |
| 38 |
|
| 39 |
|
| 40 |
DWIM, the 80% way |
| 41 |
|
| 42 |
A new configuration variable, use-inbox-flag-views. If that's set, |
| 43 |
then setting a flag in an inbox implicitly creates an eponymous view |
| 44 |
onto the inbox. |
| 45 |
|
| 46 |
|
| 47 |
Open Bug: aox add view broken |
| 48 |
|
| 49 |
Ron Peterson reports that aox add view breaks. |
| 50 |
|
| 51 |
aox add view /users/auser/someone /users/auser/archive auser address someone@gmail.com |
| 52 |
aox: Can't create view named /users/auser/someone |
| 53 |
|
| 54 |
No idea what's wrong (yet). |
| 55 |
|
| 56 |
1b149d fixed the immediate view creation problem, but the view doesn't |
| 57 |
work yet. -- AMS 20100413 |
| 58 |
|
| 59 |
Views now work, but threaded views still don't. |
| 60 |
|
| 61 |
Notify: Ron Peterson <rpeterso@mtholyoke.edu> |
| 62 |
Message-Id: <20100405132205.GL27702@mtholyoke.edu> |
| 63 |
|
| 64 |
|
| 65 |
Plaintext passwords work, sort of |
| 66 |
|
| 67 |
allow-plaintext-passwords almost works. But if we get a cleartext |
| 68 |
password and that's disallowed, we ought to treat it as bad, and |
| 69 |
notify the admin that a change of passwords is necessary. |
| 70 |
|
| 71 |
Send email to Timo when that works, he suggested the feature |
| 72 |
(unknowingly). |
| 73 |
|
| 74 |
|
| 75 |
Open bug format blah |
| 76 |
|
| 77 |
I envision the format thus: |
| 78 |
|
| 79 |
"Open Bug: " as headline prefix to mark it for the processor. |
| 80 |
|
| 81 |
The rest of the headline must never change; it'll be used to look up |
| 82 |
the web page. This is basically the bug ID. IDs can be reused as |
| 83 |
soon as the bug is closed, though. |
| 84 |
|
| 85 |
The body text contains plain old text, which will be exported, and |
| 86 |
which may be changed at will. |
| 87 |
|
| 88 |
Lines matching "Notify: " specify an email address. The email |
| 89 |
address is not published on the web site. |
| 90 |
|
| 91 |
When a commit affects a note, the script sends a notification to all |
| 92 |
specified addresses. It doesn't include the patch though. When a |
| 93 |
commit removes a note, the script says tells people "fixed". |
| 94 |
|
| 95 |
We could try to set the References field on responses... but I don't |
| 96 |
care to. It would be neat, but I don't care enough to do it. Or |
| 97 |
maybe I do. If there's a Message-ID field, we use that in |
| 98 |
References, otherwise we skip it? |
| 99 |
|
| 100 |
Is this good? |
| 101 |
|
| 102 |
|
| 103 |
P/W: Stuff we may want to keep |
| 104 |
|
| 105 |
List::take()->remove() was good |
| 106 |
|
| 107 |
also keeping iterators working |
| 108 |
|
| 109 |
Scope |
| 110 |
|
| 111 |
Having EH make a new Log by default |
| 112 |
|
| 113 |
Simplifying the way Connection objects are added to the main loop |
| 114 |
|
| 115 |
List::append( List ) -> appendList() |
| 116 |
|
| 117 |
smtpclient has simpler logic... but don't break what works |
| 118 |
|
| 119 |
cancelQuery rewrite. not sure. |
| 120 |
|
| 121 |
Do (some of) these, one at a time, making sure nothing breaks after |
| 122 |
each one. None soon. |
| 123 |
|
| 124 |
|
| 125 |
A web page about spam filtering |
| 126 |
|
| 127 |
Containing neat queries, such as "tell me whether the user with |
| 128 |
address x has mail from y not tagged as spam", or "tell me whether |
| 129 |
user x has sent mail to domain y". |
| 130 |
|
| 131 |
With aox that can be done, uniquely. So mention it. |
| 132 |
|
| 133 |
|
| 134 |
Functions and views |
| 135 |
|
| 136 |
Views that'll be good for people: |
| 137 |
- Valid local email addresses and users |
| 138 |
- Sender information |
| 139 |
- How many earlier messages from that address |
| 140 |
- How many messages to that address |
| 141 |
- How many earlier messages to/from the domain |
| 142 |
|
| 143 |
Functions: |
| 144 |
- Create user |
| 145 |
- Delete user |
| 146 |
- Rename user |
| 147 |
- Change password |
| 148 |
- Change password, given old and new password, checking |
| 149 |
- Enable/disable alias |
| 150 |
- Add/delete/rename alias |
| 151 |
|
| 152 |
|
| 153 |
Installer doesn't take steps to ensure that the installation is usable |
| 154 |
|
| 155 |
It could do at least two things: |
| 156 |
|
| 157 |
Run all the same checks on the new installation as 'aox check' and |
| 158 |
archiveopteryx at startup. |
| 159 |
|
| 160 |
Try to connect to all the server addresses and if anything's |
| 161 |
listening anywhere, mention it on stdout. |
| 162 |
|
| 163 |
In addition to this, the installer does the wrong thing right now if |
| 164 |
it creates the database users and then fails to run psql to load the |
| 165 |
schema. It exits with an error, which means the randomly-generated |
| 166 |
passwords are lost, because the configuration file is not written. |
| 167 |
|
| 168 |
|
| 169 |
db-address=localhost works, but needs improvement. |
| 170 |
|
| 171 |
- A new connect(addr, port) function resolves the given address and |
| 172 |
creates one SerialConnector object for each result. It starts the |
| 173 |
first one, which (after an error, or a delay of 1s) initiates the |
| 174 |
next connection in line and so on. The first one to connect swaps |
| 175 |
out the d of the original connection with its own, and makes the |
| 176 |
EventLoop act as though it had just connected. |
| 177 |
|
| 178 |
It works, but the code is a little ugly. The error handling logic |
| 179 |
needs a careful look after some time. Once that's solid, the other |
| 180 |
callers (SpoolManager/SmtpClient etc.) can be converted. |
| 181 |
|
| 182 |
|
| 183 |
aox check schema |
| 184 |
|
| 185 |
This command would check several things. |
| 186 |
|
| 187 |
a) that dbuser has the needed rights |
| 188 |
b) that all the right tables are there, and all the right columns, |
| 189 |
with the right types, and no unexpected constraints |
| 190 |
c) that all the right indexes are there |
| 191 |
d) that dbowner owns everything |
| 192 |
i) that inserts that would duplicate a constraint are properly |
| 193 |
recognised |
| 194 |
|
| 195 |
As a bonus, perhaps it could list some unexpected/unknown deviations: |
| 196 |
e) locally added tables |
| 197 |
f) locally added columns |
| 198 |
g) locally added indices |
| 199 |
h) missing constraints |
| 200 |
|
| 201 |
Change 43939 and following move towards this: the idea is to |
| 202 |
introduce new functions e.g. Schema::checkIntegrity (in addition to |
| 203 |
checkRevision) and Schema::grantPrivileges, that can be used both by |
| 204 |
aox check schema/aox grant privileges/whatever, and also by the |
| 205 |
installer (instead of lib/grant-privileges, and instead of the |
| 206 |
half-hearted checking it does now). the server is essentially |
| 207 |
unaffected, it just uses Database::checkSchema/checkAccess for a |
| 208 |
quick check. |
| 209 |
|
| 210 |
this sounds ok, but it's ugly because Schema::execute is completely |
| 211 |
given to upgrading the schema, and neither can nor should be |
| 212 |
repurposed to do other things besides. so that means more static |
| 213 |
functions in Schema and separate EventHandlers to do the |
| 214 |
checking/granting/whatevering. but that's okay. |
| 215 |
|
| 216 |
|
| 217 |
The \Answered flag |
| 218 |
|
| 219 |
We could add a little code to help that flag. |
| 220 |
|
| 221 |
1. Disallow clearing it once set. |
| 222 |
2. Set it on messages when we see an outgoing reply. |
| 223 |
|
| 224 |
This would make it easier to force archiving. |
| 225 |
|
| 226 |
|
| 227 |
5255 |
| 228 |
|
| 229 |
We already inplement I18NLEVEL=1, so I advertised that. I18NLEVEL=2 |
| 230 |
doesn't seem very useful. I also don't know how to do that in SQL. |
| 231 |
|
| 232 |
|
| 233 |
Other RFCs |
| 234 |
|
| 235 |
I think we need to consider these RFCs, or at least mention them |
| 236 |
somewhere in the documentation so we know we've considered them: |
| 237 |
|
| 238 |
821 |
| 239 |
934 (?) |
| 240 |
974 |
| 241 |
1049 (should be handled fine, so check and mention) |
| 242 |
1641 (old mime?) |
| 243 |
1731 (old imap?) |
| 244 |
1893 (ditto) |
| 245 |
1894 (older version of something we handle, right?) |
| 246 |
2044 (?) |
| 247 |
2068 (HTTP? surely we do that) |
| 248 |
2222 |
| 249 |
2244 |
| 250 |
|
| 251 |
|
| 252 |
Cleartext passwords |
| 253 |
|
| 254 |
We help migrating away from cleartext/plaintext passwords: |
| 255 |
|
| 256 |
1. We also store SCRAM and similar secrets in the DB (secrets which |
| 257 |
aren't password equivalents) |
| 258 |
2. We extend the users table with two new columns, 'last time |
| 259 |
cleartext was needed' and 'number of successful authentications |
| 260 |
without cleartext password usage since cleartext'. |
| 261 |
3. If a client uses SCRAM, we increment the counter. |
| 262 |
4. If a client uses CRAM or PLAIN, we reset counter and set the time |
| 263 |
to today. |
| 264 |
5. We provide some helping code to delete passwords for users with a |
| 265 |
high count and a long-ago time. |
| 266 |
6. We add documentation saying that if you disable auth-this and |
| 267 |
auth-that, you can disable store-plaintext-passwords. |
| 268 |
7. We add configuration/db sanity checks for ditto. |
| 269 |
|
| 270 |
|
| 271 |
Database schema range |
| 272 |
|
| 273 |
People occasionally need to access the db with an old version of |
| 274 |
mailstore. I suggest that we: |
| 275 |
|
| 276 |
a) add a 'writable_from' column specifying the oldest version that |
| 277 |
can write to the database. |
| 278 |
b) add a 'readable_from' column specifying the oldest version that |
| 279 |
can read the database |
| 280 |
|
| 281 |
aox upgrade schema would update writable_from to the oldest schema |
| 282 |
version for which a writer would do the right job. This would often |
| 283 |
change when a table changes, but not when a table is added. |
| 284 |
|
| 285 |
readable_from would be the oldest revision that can read the database. |
| 286 |
|
| 287 |
When the server starts up, it would check: |
| 288 |
|
| 289 |
- am I >writable_from? If so, mailboxes can be read-write |
| 290 |
- else, am I >readable_from? If so, startup can proceed, but all |
| 291 |
mailboxes are read-only. lmtp, smtp and smtp-submit do not start. |
| 292 |
- else, quit. |
| 293 |
|
| 294 |
And in order to handle database updates, I suggest another table, |
| 295 |
'features', with a single string column. When aox update database |
| 296 |
fixes something, it inserts a row into features. A modern database |
| 297 |
would have two rows in this table, 'numbered address fields' and 'no |
| 298 |
nulls in bodyparts'. |
| 299 |
|
| 300 |
|
| 301 |
Reject or ereject may want MDNs instead of DSNs |
| 302 |
|
| 303 |
Our sieve code generates DSNs if it can't generate protocol-level |
| 304 |
refusal, which it always can in practice. MDNs should be used in at |
| 305 |
least some cases, if a non-zero percentage of zero can be considered |
| 306 |
"some cases". |
| 307 |
|
| 308 |
|
| 309 |
Message tracking |
| 310 |
|
| 311 |
RFCs 3885-8 specify ways to track messages that have been sent. We |
| 312 |
can implement that fairly easily. |
| 313 |
|
| 314 |
If we route outgoing mail via a smarthost, that smarthost has to |
| 315 |
support MTRK in order for tracking to work well. |
| 316 |
|
| 317 |
We can track mail provided that at least one of these is true: |
| 318 |
|
| 319 |
- we deliver directly to the end server (we don't know whether |
| 320 |
that's the case, though) |
| 321 |
|
| 322 |
- we deliver via an MTRK-capable server |
| 323 |
|
| 324 |
- we deliver into our own database |
| 325 |
|
| 326 |
Sounds likely to be true maybe 80-90% of the time. |
| 327 |
|
| 328 |
If none are true, we can at least say, easily, where we delivered, |
| 329 |
when, and why. |
| 330 |
|
| 331 |
We could implement the tracking protocol (and I'd write a query blah |
| 332 |
in mailchen), and also provide a query interface via the web. |
| 333 |
|
| 334 |
|
| 335 |
Message tracking 2 |
| 336 |
|
| 337 |
We can recognize the ESMTP id for the most common MTAs. Postfix says: |
| 338 |
|
| 339 |
250 Ok: queued as D1A324AC85 |
| 340 |
|
| 341 |
Sendmail and exim surely say something similar. We could keep that ID |
| 342 |
in delivery_recipients and use it in DSNs. |
| 343 |
|
| 344 |
|
| 345 |
Generating bounces |
| 346 |
|
| 347 |
Our bounces would look better if they included the entire SMTP |
| 348 |
conversation (starting with RSET or EHLO). |
| 349 |
|
| 350 |
|
| 351 |
Bounces and DSNs |
| 352 |
|
| 353 |
Mail is currently fairly reliable. There is one big exception: |
| 354 |
Bounces aren't 100% parsable. But generally, if you work hard, you |
| 355 |
can know whether a message was delivered or not, and mostly they are |
| 356 |
delivered. |
| 357 |
|
| 358 |
So we benefit from converting the most common nonstandard bounces to |
| 359 |
DSNs, and then treat them as DSNs. |
| 360 |
|
| 361 |
For nonstandard bounces (like those of qmail) we identify the |
| 362 |
message by trying hard, do some hacky parsing, use the bounce |
| 363 |
(excluding trailing message) as first part of the DSN multipart, |
| 364 |
cook up a new DSN report based on the parsing, and save |
| 365 |
text/822-headers as a third part. |
| 366 |
|
| 367 |
Then, searches that tie bounces together with messages sent work |
| 368 |
even better. |
| 369 |
|
| 370 |
(Another trick we can/should use is to see whether the host we |
| 371 |
deliver to seems to be the final destination based on earlier |
| 372 |
(answered) messages.) |
| 373 |
|
| 374 |
|
| 375 |
RFC 2554 |
| 376 |
|
| 377 |
Have to look closer at that, I hadn't grasped the MAIL FROM AUTH |
| 378 |
issue and there may be more. |
| 379 |
|
| 380 |
addParams( "auth", ... ) in MAIL FROM needs consideration. Not |
| 381 |
important. |
| 382 |
|
| 383 |
|
| 384 |
imapd/handlers/acl.cpp |
| 385 |
|
| 386 |
Different tasks, some shared code, same file. Separate this out into |
| 387 |
different classes inheriting something. Then add the right sort of |
| 388 |
logging statement to the end of parse(). |
| 389 |
|
| 390 |
|
| 391 |
Threads in Archiveopteryx 4.0 |
| 392 |
|
| 393 |
I'm growing more and more fond of using a few threads, and not using |
| 394 |
server-processes any more. We'd replace server-processes with |
| 395 |
server-threads, or just keep the name. |
| 396 |
|
| 397 |
The core event loop would create a queue of work to be done based on |
| 398 |
which file descriptors have input, and worker threads would take a |
| 399 |
piece of work, obtain the fd's lock, and do it. |
| 400 |
|
| 401 |
The Query would have a optional Connection pointer, the Transaction |
| 402 |
would have a mandatory one. Scope would probably have one. Perhaps |
| 403 |
Q+T could copy Scope's. A worker thread which processes database |
| 404 |
input would have to obtain the lock for the scope's fd whenever it |
| 405 |
enters the scope. |
| 406 |
|
| 407 |
We'd be able to collect garbage without halts. Large IMAP Fetch |
| 408 |
commands would also not cause halts. We'd be able to serve all |
| 409 |
clients fairly, using all cores, using fewer database backends than |
| 410 |
with server-processes. |
| 411 |
|
| 412 |
The Apple Autozone GC looks good for this. |
| 413 |
|
| 414 |
The default for server-processes ought to change to match the number |
| 415 |
of processors: |
| 416 |
|
| 417 |
Linux, Solaris, & AIX (per comments): |
| 418 |
numCPU = sysconf( _SC_NPROCESSORS_ONLN ); |
| 419 |
|
| 420 |
FreeBSD, macosx, NetBSD, OpenBSD, etc.: |
| 421 |
int mib[4]; |
| 422 |
size_t len; |
| 423 |
|
| 424 |
/* set the mib for hw.ncpu */ |
| 425 |
mib[0] = CTL_HW; |
| 426 |
mib[1] = HW_AVAILCPU; // alternatively, try HW_NCPU; |
| 427 |
|
| 428 |
/* get the number of CPUs from the system */ |
| 429 |
sysctl(mib, 2, &numCPU, &len, NULL, 0); |
| 430 |
|
| 431 |
if( numCPU < 1 ) |
| 432 |
{ |
| 433 |
mib[1] = HW_NCPU; |
| 434 |
sysctl( mib, 2, &numCPU, &len, NULL, 0 ); |
| 435 |
|
| 436 |
if( numCPU < 1 ) |
| 437 |
numCPU = 1; |
| 438 |
} |
| 439 |
|
| 440 |
|
| 441 |
Full-text search |
| 442 |
|
| 443 |
There Be Problems. |
| 444 |
|
| 445 |
The code now assumes that the IMAP client searches for one or more |
| 446 |
words, rather than an arbitrary substring. Postgres uses word |
| 447 |
segmentation. |
| 448 |
|
| 449 |
If postgres were to use e.g. overlapping three-letter languageless |
| 450 |
substrings, we would do what IMAP wants. sounds senseless. |
| 451 |
|
| 452 |
We also have a requirement to stem search arguments less. |
| 453 |
Specifically, a search for ARM7TDMI should not return messages about |
| 454 |
the ARM6 or about my left arm. |
| 455 |
|
| 456 |
|
| 457 |
Convert more parsers to use AbnfParser |
| 458 |
|
| 459 |
There are still a few places where we roll our own messy parsers and |
| 460 |
suffer for it (e.g. HTTP, DigestMD5). We know they work, but making |
| 461 |
them use AbnfParser in a spare moment would be an act of kindness. |
| 462 |
|
| 463 |
|
| 464 |
aox/conf/tls-certificate |
| 465 |
|
| 466 |
Those variables are not well described. We need a bit more. |
| 467 |
|
| 468 |
Also, -secret is probably misnamed, we use -password for other |
| 469 |
cases. I expect that's why aox show cf tls-certificate-secret yields |
| 470 |
while e.g. aox show cf db-password does not. |
| 471 |
|
| 472 |
|
| 473 |
METADATA |
| 474 |
|
| 475 |
Needed for lemonade, as easy as annotate. |
| 476 |
|
| 477 |
|
| 478 |
Autoresponder |
| 479 |
|
| 480 |
We have vacation now, but it isn't quite right for autoresponses. |
| 481 |
Sieve autorespond should be like this: |
| 482 |
|
| 483 |
1. :quote should quote the first text/plain part if all of the |
| 484 |
following are true: |
| 485 |
|
| 486 |
1. The message is signed, and the signature verified (using any |
| 487 |
supported signature mechanism, DKIM SHOULD be supported). |
| 488 |
2. The first text/plain part does not have a Content-Disposition |
| 489 |
other than inline. |
| 490 |
|
| 491 |
If any of the conditions aren't true, :quote shouldn't quote. |
| 492 |
|
| 493 |
If there's a signature block, :quote shouldn't quote that. |
| 494 |
|
| 495 |
If the quoted text would be more than ten lines, :quote may crop |
| 496 |
it down as much as it wants, ideally by skipping lines starting |
| 497 |
with '>', otherwise by removing the last lines. |
| 498 |
|
| 499 |
2. :subject, :from and :addresses as for vacation. |
| 500 |
|
| 501 |
3. :cc can be used to send a copy to the specified From address. |
| 502 |
|
| 503 |
4. The default :handle should not be based on the quoted text. |
| 504 |
|
| 505 |
5. Two text arguments, one for text before the quoted text, one for |
| 506 |
text after the quoted text. |
| 507 |
|
| 508 |
6. The autoresponse goes to the envelope sender, as some RFC |
| 509 |
requires. So we want an option to skip the response unless the |
| 510 |
return-path matches reply-to (if present) or From (unless |
| 511 |
reply-to is present). |
| 512 |
|
| 513 |
|
| 514 |
Message arrival tag |
| 515 |
|
| 516 |
Once annotate is done, we want a tag, ie. a magic annotation which |
| 517 |
stays glued to the message wherever it goes, even after copy/move. |
| 518 |
|
| 519 |
We also want a way to store the original RFC822 format somewhere |
| 520 |
inside and/or outside the database, indexed by the arrival tag |
| 521 |
identifier. It's good if the tag is split, so we can have "x-y" |
| 522 |
where X is the CD/DVD number and Y is the file on the CD/DVD. Or |
| 523 |
something like that. |
| 524 |
|
| 525 |
|
| 526 |
Sieve ihave |
| 527 |
|
| 528 |
There are three holes in our ihave rules. |
| 529 |
|
| 530 |
Single-child anyof doesn't promote the ihave: |
| 531 |
|
| 532 |
if anyof( ihave "foo" ) { |
| 533 |
foo; # errors should not be reported here |
| 534 |
} |
| 535 |
|
| 536 |
Not doesn't promote: |
| 537 |
|
| 538 |
if not not ihave "foo" { |
| 539 |
foo; # errors should not be reported here |
| 540 |
} |
| 541 |
|
| 542 |
Finally, if/elsif always applies the ihave to its own block, instead |
| 543 |
of walking along elsif/else to find the block that might be executed |
| 544 |
if ihave returns true: |
| 545 |
|
| 546 |
if not ihave "foo" { |
| 547 |
# errors should be reported here |
| 548 |
} else { |
| 549 |
foo; # but not here |
| 550 |
} |
| 551 |
|
| 552 |
|
| 553 |
C/R |
| 554 |
|
| 555 |
C/R sucks. But it has its uses, so we can benefit from implementing |
| 556 |
it somehow. Here are some classes of messages we may want to treat |
| 557 |
specially: |
| 558 |
|
| 559 |
- replies to own mail |
| 560 |
- messages in languages not understood by the user |
| 561 |
- mail from previously unknown addresses |
| 562 |
- mail from freemail providers |
| 563 |
- vacation responses from unknowns |
| 564 |
- messages likely, but not certain to be out-of-office-autoreply |
| 565 |
- dkim/mass-signed messages (if verified) |
| 566 |
|
| 567 |
The questions are: How can we ensure that we almost never challenge |
| 568 |
real mail, while simultaneously challenging most/all messages that |
| 569 |
don't come from valid senders? How can we provide suitable |
| 570 |
configuration? |
| 571 |
|
| 572 |
Mail from freemail vendors tends to have a "Received: ... via HTT" |
| 573 |
field. |
| 574 |
|
| 575 |
|
| 576 |
Squirrelmail |
| 577 |
|
| 578 |
Inefficiency has a name. |
| 579 |
|
| 580 |
1. Too many LOGINs. We can cache Users using a Cache, that'll solve |
| 581 |
that. But LOGIN isn't that slow, so I'm not sure it's worth it. |
| 582 |
|
| 583 |
2. Too many SELECTs and EXAMINEs. SessionCAche and FirstUnreadCache |
| 584 |
solve that. |
| 585 |
|
| 586 |
3. Too many EXPUNGEs. If we keep a "last expunged at modseq" in |
| 587 |
ImapSession, check and set it in Expunge, and check and set it in |
| 588 |
store ("if the last expunge was the previous modseq, and I'm not |
| 589 |
adding any \deleted flags, then increase"), then we can turn |
| 590 |
those expunges into noops. |
| 591 |
|
| 592 |
That should speed up SM and probably other webmail systems nicely. |
| 593 |
|
| 594 |
|
| 595 |
Using rrdtool |
| 596 |
|
| 597 |
What could we want to graph with rrdtool? Lots. |
| 598 |
|
| 599 |
- CPU seconds used |
| 600 |
- database size |
| 601 |
- messages in the db |
| 602 |
- average response time |
| 603 |
- 95th percentile response time |
| 604 |
- messages per user |
| 605 |
- message size per user |
| 606 |
- average query execution time |
| 607 |
- average query queue size |
| 608 |
|
| 609 |
More? |
| 610 |
|
| 611 |
http://jwatt.org/svg/authoring/ is interesting for generating graphs |
| 612 |
via the web interface. |
| 613 |
|
| 614 |
|
| 615 |
We should be able to use a read-only local database mirror. |
| 616 |
|
| 617 |
That way, we can play nicely with most replication systems. |
| 618 |
|
| 619 |
The way to do it: add a new db-mirror setting pointing to a |
| 620 |
read-only database mirror. all queries that update are sent to |
| 621 |
db-address, all selects are sent to db-mirror. db-mirror defaults to |
| 622 |
db-address. |
| 623 |
|
| 624 |
|
| 625 |
We should test multipart/signed and multipart/encrypted support. |
| 626 |
|
| 627 |
We must add a selection of RFC 1847 messages to canonical, and make |
| 628 |
sure they survive the round trip. No doubt there will be bugs. |
| 629 |
|
| 630 |
|
| 631 |
Per-user client certificates |
| 632 |
|
| 633 |
We could store zero or more client certificates (or fingerprints, or |
| 634 |
whatever) per user. When a user has logged in, we'd check whether |
| 635 |
that user has a non-zero list of certificates, and if so, we'd do a |
| 636 |
TLS renegotiation, this time demanding a client certificate. If the |
| 637 |
client certificate matches, we allow access, otherwise we don't (and |
| 638 |
we alert the user). |
| 639 |
|
| 640 |
A bit difficult to do with the hands-off tlsproxy. |
| 641 |
|
| 642 |
|
| 643 |
We should store bodyparts.text for PDF/DOC. |
| 644 |
|
| 645 |
We need non-GPLed code to convert PDF and DOC to plaintext. |
| 646 |
|
| 647 |
Or maybe we need a generic interface to talk to plugins. |
| 648 |
|
| 649 |
|
| 650 |
Switch to using named constraints everywhere. |
| 651 |
|
| 652 |
|
| 653 |
Default c-t-e of PGP signatures |
| 654 |
|
| 655 |
Right now we give them binary. q-p or 7bit would be better, I think. |
| 656 |
|
| 657 |
What other application/* types are really text? |
| 658 |
|
| 659 |
From a conversation the other day: we could avoid base64 encoding an |
| 660 |
entity whose content-type is not text if it contains only printable |
| 661 |
ASCII. I don't know if it's worth doing, though. |
| 662 |
|
| 663 |
The problem with doing that is that it treats sequences of CR LF, CR |
| 664 |
and LF as equivalent. An application/foobar object that happens to |
| 665 |
contain only CR, LF and printable ASCII can be broken. |
| 666 |
|
| 667 |
|
| 668 |
Recognising spam |
| 669 |
|
| 670 |
The good spam filters now all seem to require local training with |
| 671 |
both spam and nonspam corpora. We can do clever stuff... sometimes. |
| 672 |
|
| 673 |
Instead of filtering at delivery, we can filter when a message |
| 674 |
becomes \recent. When we increase first_recent, we hand each new |
| 675 |
message to the categoriser, and set $Spam or $Nonspam based on its |
| 676 |
answer. |
| 677 |
|
| 678 |
This lets the categoriser use all the information that's available |
| 679 |
right up to the moment the user looks at his mail. |
| 680 |
|
| 681 |
We can also build corpora for training easily. All messages to which |
| 682 |
users have replied are nonspam, replies to messages from local users |
| 683 |
are nonspam, messages in certain folders are spam, messages with a |
| 684 |
certain flag are spam. |
| 685 |
|
| 686 |
We can connect to a local server to ask whether a message is spam. |
| 687 |
They seem to work that way, but with n different protocols. |
| 688 |
|
| 689 |
|
| 690 |
"Writing Secure Code" |
| 691 |
|
| 692 |
We have a page about security, /mailstore/security.html, and a |
| 693 |
section of the mailstore.7 man page mentions it too. |
| 694 |
|
| 695 |
We need to look at ISBN 0735617228 and improve security.html with |
| 696 |
points from it. It could also be that we'll improve the code itself. |
| 697 |
|
| 698 |
|
| 699 |
Faster mapping from unicode to 8-bit encodings |
| 700 |
|
| 701 |
At the moment, we use a while loop to find the right codepoint in an |
| 702 |
array[256]. Mapping U+00EF to latin-1 requires looping from 0 to |
| 703 |
0xEF, checking those 239 entries. |
| 704 |
|
| 705 |
We could use a DAG of partial mappings to make it faster. Much |
| 706 |
faster. Mapping U+20AC to 8895-15 would require just one lookup: In |
| 707 |
the first partial table for 8859-15. Mapping U+0065 to 8859-15 would |
| 708 |
require three: In the first (U+20AC, one entry long), in the |
| 709 |
fallback (U+00A0, 96 entries long) and in the last (U+0000, 160 |
| 710 |
entries long). |
| 711 |
|
| 712 |
Effectively, 8859-15 would be a first table of exceptions and then |
| 713 |
fall back to 8859-1. |
| 714 |
|
| 715 |
The tables could be built automatically, compiled in, and would be |
| 716 |
tested by our existing apparatus. |
| 717 |
|
| 718 |
Or we could do it simpler and perhaps even faster: Make a local |
| 719 |
array from unicode to target at the start, fill it in as we go, and |
| 720 |
do the slow scan only when we see a codepoint for the first time. |
| 721 |
|
| 722 |
|
| 723 |
Multipart/signed automatic processing |
| 724 |
|
| 725 |
We could check signatures automatically on delivery, and reject bad |
| 726 |
signed messages. |
| 727 |
|
| 728 |
The big benefit is that some forgeries are rejected, even though the |
| 729 |
reader and the reading MUA doesn't do anything different. |
| 730 |
|
| 731 |
The disadvantage is that we (probably?) can't verify all signatures, |
| 732 |
which gives a false sense of security for the undetectable forgeries. |
| 733 |
|
| 734 |
In case of PKCS7, it's possible to self-sign. Those we cannot |
| 735 |
check. In that case we remove the signature entirely from the MIME |
| 736 |
structure, so it doesn't look checked to the end-user. |
| 737 |
|
| 738 |
PGP cannot be checked, except it sort of can. We can have a small |
| 739 |
default keyring including the heise.de CA key and so on, and treat |
| 740 |
that as root CAs, using the keyservers to dig up intermediate keys. |
| 741 |
|
| 742 |
|
| 743 |
PGP automatic processing |
| 744 |
|
| 745 |
Apparently there are five different PGP wrapping formats. We could |
| 746 |
detect four and transform them to the proper MIME format. |
| 747 |
|
| 748 |
|
| 749 |
Plugins |
| 750 |
|
| 751 |
It's not given that we want to accept all mail. If we don't, who |
| 752 |
makes the decision? A sieve script may, and refuse/reject mail it |
| 753 |
does not like. And a little bit of pluginnery may. I think we'd do |
| 754 |
well to support the postfix plugin protocol, so all postfix policy |
| 755 |
servers can work with aox. (All? Or just half? Doesn't postfix have |
| 756 |
two types of policy plugins?) |
| 757 |
|
| 758 |
We may even support site-wide and group-wide sieve scripts and |
| 759 |
permit a sieve script to invoke the plugin. A sieve statement like |
| 760 |
this? |
| 761 |
|
| 762 |
UsePolicyServer localhost 10023 ; |
| 763 |
|
| 764 |
|
| 765 |
BURL |
| 766 |
|
| 767 |
If the message is multipart and the boundary occurs in a part, that |
| 768 |
part needs encoding. Or else switch to a different body. |
| 769 |
|
| 770 |
|
| 771 |
Delaying seen-flag setting |
| 772 |
|
| 773 |
We can move the seenflagsetter to imapsession, build up flags to |
| 774 |
set, flush the write cache before fetch flags, store, state-altering |
| 775 |
commands and searches which use either modseq or flags. |
| 776 |
|
| 777 |
This ought to cut down the number of transactions issued per imap |
| 778 |
command nicely. |
| 779 |
|
| 780 |
|
| 781 |
Sending forged From despite check-sender-addresses |
| 782 |
|
| 783 |
vacation :from and notify :mailto :from don't check |
| 784 |
|
| 785 |
The injector probably needs to get the logic from the smtp server. |
| 786 |
|
| 787 |
|
| 788 |
Per-group and systemwide sieves |
| 789 |
|
| 790 |
People always seem to want such things. It'll be easy to implement. |
| 791 |
Most of the tricky issues are described in |
| 792 |
http://tools.ietf.org/html/draft-degener-sieve-multiscript-00 |
| 793 |
|
| 794 |
|
| 795 |
The Sieve "header" test may fail |
| 796 |
|
| 797 |
Write a test or three that feeds the thing a 2047-encoded header |
| 798 |
field and checks that it's correctly matched/not matched. Then make |
| 799 |
it pass. |
| 800 |
|
| 801 |
|
| 802 |
The subaddress specification says foo@ != foo+@ wrt. :detail |
| 803 |
|
| 804 |
The former causes any :detail tests to evaluate to false, while the |
| 805 |
latter treats :detail as an empty string. We treat both as an empty |
| 806 |
string. |
| 807 |
|
| 808 |
(We could set detail to a single null byte, to \0\r\0\n\0, to a |
| 809 |
sequence of private-use unicode characters, or even to |
| 810 |
Entropy::string( 8 ) if there is no separator. The chance of that |
| 811 |
appearing in an address is negligible.) |
| 812 |
|
| 813 |
|
| 814 |
SMTP extensions |
| 815 |
|
| 816 |
Here are the ones we still don't implement, but ought to implement |
| 817 |
at some point: |
| 818 |
|
| 819 |
DELIVERBY (RFC 2852): At some time. |
| 820 |
MTRK: As soon as someone else does it. |
| 821 |
|
| 822 |
http://www.iana.org/assignments/mail-parameters |
| 823 |
|
| 824 |
DELIVERBY has the funny little characteristic that we can support it |
| 825 |
with great ease iff the smarthost does, so we ought to advertise iff |
| 826 |
if the smarthost does. |
| 827 |
|
| 828 |
|
| 829 |
The groups and group_members tables seem a little underused |
| 830 |
|
| 831 |
We do not use them at all. We meant to use them for "advanced" ACL |
| 832 |
support, but nobody ever asked, and it didn't seem worthwhile. |
| 833 |
|
| 834 |
I now think it's worthwhile. |
| 835 |
|
| 836 |
Here's what I want to add: |
| 837 |
|
| 838 |
Make a superusers group, which members can authenticate as anyone, |
| 839 |
and the notion of group admins, who can authenticate as other |
| 840 |
members of the group. |
| 841 |
|
| 842 |
Or maybe an administrator table, linking a user to either a group or |
| 843 |
to null. If a group, then the admin can authenticate as other |
| 844 |
members of that group and (importantly) has 'a' right on their |
| 845 |
mailboxes, if null, then ditto for all groups. |
| 846 |
|
| 847 |
Extend Permissions to link against group_members when selecting |
| 848 |
applicable permissions. |
| 849 |
|
| 850 |
Make groups be permissible ACL identifiers. |
| 851 |
|
| 852 |
|
| 853 |
We need to be able to disable users |
| 854 |
|
| 855 |
- Reject mail with 5xx/4xx. |
| 856 |
- Prevent login. |
| 857 |
- 1+2. |
| 858 |
- a group admin can enable/disable group members |
| 859 |
- a superadmin can enable/disable anyone |
| 860 |
- a group admin cannot unblock an overall blockage |
| 861 |
|
| 862 |
|
| 863 |
aox.org/badmail/ |
| 864 |
|
| 865 |
Explain that aox can't store everything, why not (in short), that it |
| 866 |
has many workarounds and point to examples/, how to detect/report |
| 867 |
bad messages and how to fix things with reparse. Point to |
| 868 |
/aox/reparse for more detail. |
| 869 |
|
| 870 |
Subpages: |
| 871 |
|
| 872 |
badmail/examples/n for 1<=n<=8, with good and bad blah, generated |
| 873 |
from chosen canonicals, to show how we fix things up. Each page |
| 874 |
showing old and new, with differences indicated, and they should be |
| 875 |
ordered from reasonable/common to outrageous. |
| 876 |
|
| 877 |
badmail/examples/ summing up 1-8 and giving one or two truly |
| 878 |
hopeless cases. The hopeless case(s) should also be shown in |
| 879 |
anonymised form. |
| 880 |
|
| 881 |
badmail/examples/comparison if I feel nasty and bored one day, |
| 882 |
showing how a few IMAP servers handle messages 1-8 and the |
| 883 |
impossible one(s). Does "fetch envelope" return the right thing? |
| 884 |
"fetch bodystructure"? Some choice searches? We don't want to link |
| 885 |
to this page very much. It gets a fine <table> containing many/few |
| 886 |
✓ cells. |
| 887 |
|
| 888 |
Possibly we want to include screenshots showing how Thunderbird or |
| 889 |
another GUI client that uses envelope/bodystructure renders a |
| 890 |
mailbox containing 1-8. Screenshots using aox and using another |
| 891 |
server, one that gets few ✓ cells in the table. I'm not sure |
| 892 |
where to link to these screenshots. Apple Mail? |
| 893 |
|
| 894 |
We also need aox.org/aox/reparse and I suppose other /aox/<command> |
| 895 |
pages. |
| 896 |
|
| 897 |
|
| 898 |
Dynamically preparing often-used queries |
| 899 |
|
| 900 |
We can prepare queries cleverly. |
| 901 |
|
| 902 |
Inside Query, at submit time, we first check whether a Query's text |
| 903 |
matches a PreparedStatement, and uses it if so. |
| 904 |
|
| 905 |
If not, we check whether the query looks preparable. The condition |
| 906 |
seems to be simple: Starts with 'select ' and contains no numbers. |
| 907 |
If it's preparable we add it to a cache, which is discarded at GC |
| 908 |
time. |
| 909 |
|
| 910 |
If a preparable query is used more than n times before the cache is |
| 911 |
discarded, we prepare the query and keep the PreparedStatement |
| 912 |
around. |
| 913 |
|
| 914 |
|
| 915 |
Defending against PGP Desktop and similar |
| 916 |
|
| 917 |
There are several more things to do: |
| 918 |
|
| 919 |
- Guess that it's repeating a query for smallish UID sets and do the |
| 920 |
query once and for all. |
| 921 |
|
| 922 |
- Defend against 'OR BODY asdf BODY asd' by recognising in |
| 923 |
simplify() that when asd matches, asdf always will. Added bonus |
| 924 |
for the base64 shit. |
| 925 |
|
| 926 |
- Hack in Search::parse() for that/those specific search keys, and |
| 927 |
setting up a more sensible selector. |
| 928 |
|
| 929 |
The first two make sense IMO. |
| 930 |
|
| 931 |
|
| 932 |
SMS gateway |
| 933 |
|
| 934 |
We want Archiveopteryx to work as installed. We want to support |
| 935 |
Sieve notify, including SMS. |
| 936 |
|
| 937 |
I think that means we need to operate an Archiveopteryx->SMS |
| 938 |
gateway, allow people do send a few SMSes, and provide people with |
| 939 |
the ability to operate a gateway of their own. |
| 940 |
|
| 941 |
There are many IP->SMS gateways in the world. Some free, but we |
| 942 |
don't want to use those, they're unreliable. Many paid for, those |
| 943 |
are reliable. Most of them work using HTTP requests: You POST a |
| 944 |
query with your credentials and the gateway reports. |
| 945 |
|
| 946 |
So my plan is as follows: |
| 947 |
|
| 948 |
1. Become a customer of someone like that. |
| 949 |
|
| 950 |
2. Write a program which accepts requests in a format we define, |
| 951 |
forwards them in the HTTP-based format our provider uses, and |
| 952 |
relays the response back. |
| 953 |
|
| 954 |
3. Provide that service to new Archiveopteryx installations, with |
| 955 |
limitations on use. |
| 956 |
|
| 957 |
4. Provide the gateway program along with Archiveopteryx, so people |
| 958 |
can run it themselves. |
| 959 |
|
| 960 |
I haven't thought of a good way to provide the service to |
| 961 |
Archiveopteryx users and weed out most other people. |
| 962 |
|
| 963 |
Perhaps a better alternative: Automatically register with clickatell |
| 964 |
if SMS is enabled and not configured when it's first used. (But it's |
| 965 |
not possible to register with clickatell without intervention.) |
| 966 |
|
| 967 |
|
| 968 |
New RFCs |
| 969 |
|
| 970 |
5463: sieve ihave |
| 971 |
5490: sieve metadata |
| 972 |
|
| 973 |
5442: lemonade profile-bis |
| 974 |
|
| 975 |
|
| 976 |
Sieve notify |
| 977 |
|
| 978 |
5435: sieve notify |
| 979 |
5436: sieve notify mailto |
| 980 |
5437: sieve notify xmpp |
| 981 |
|
| 982 |
mailto: combined with :from is unchecked |
| 983 |
|
| 984 |
|
| 985 |
Bug confusing U+ED00 and U+0000 in the message cache |
| 986 |
|
| 987 |
When we write to the database, U+0000 (which occasionally occurs, |
| 988 |
mostly by mistake but sometimes on purpose) is transformed to |
| 989 |
U+ED00, and when we read it, back. |
| 990 |
|
| 991 |
So if U+ED00 is written to the DB, it comes back as U+0000. |
| 992 |
|
| 993 |
This means that Archiveopteryx works differently depending on |
| 994 |
whether the cache is used or not. That has to be resolved somehow. |
| 995 |
|
| 996 |
|
| 997 |
Axel, /Mime problem |
| 998 |
|
| 999 |
The problem is that the VCF file contains literal NUL bytes, but is |
| 1000 |
sent with a text/* MIME type, and we're mangling the NULs during |
| 1001 |
charset conversion (or so I guess, given that they become '?'s |
| 1002 |
instead). |
| 1003 |
|
| 1004 |
|
| 1005 |
Various alias-related feature requests |
| 1006 |
|
| 1007 |
e.g. Benjamin wants empty localparts, a number of people want multiple |
| 1008 |
targets (Axel, Ingo). |
| 1009 |
|
| 1010 |
|
| 1011 |
Axel, /Unable to fetch 12MB mail |
| 1012 |
|
| 1013 |
Some sort of loop in the fetcher? I didn't look. |
| 1014 |
|
| 1015 |
|
| 1016 |
Problems found in 3.0.0 by Timo |
| 1017 |
|
| 1018 |
- SEARCH SENTON/SENTBEFORE/SENTAFTER have some bugs. |
| 1019 |
(Not verified because of segfault; will check later.) |
| 1020 |
|
| 1021 |
Not fixed; I lean towards fixing it if it's the only thing |
| 1022 |
imaptest complains about. |
| 1023 |
|
| 1024 |
|
| 1025 |
Use current_setting('server_version_num') instead of parsing version() |
| 1026 |
|
| 1027 |
(But only under 8.2+) |
| 1028 |
|
| 1029 |
|
| 1030 |
Caching search results |
| 1031 |
|
| 1032 |
If a selector is !dynamic(), its results can be cached until the next |
| 1033 |
modseq change on the mailbox. |
| 1034 |
|
| 1035 |
|
| 1036 |
Bugs |
| 1037 |
|
| 1038 |
- "aox start" doesn't complain when there's a schema mismatch error. |