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
  &#x2713; 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 &#x2713; 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.