�ɲɾ�����ӯ�����һ��ˣ��������С���˴��ͣ�������P���ҹ��ñ˽��ά�Բ��������˸߸ԣ�������ơ��ҹ��ñ�����ά�Բ���ˡ���˳^�ӣ������ӡ� ���ͯj�ӣ��ƺ���ӣ� ? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!bugs.txt000064400000027265152527400360006265 0ustar00/* ======================================================================== * Copyright 1988-2007 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ KNOWN BUGS/MISFEATURES/DEFICIENCIES IN THE IMAP TOOLKIT Last Updated: 15 November 2007 The following are known problems/deficiencies in the imap-2007 toolkit: . Possible problems for some installations: . In some versions of Redhat Linux, SVR4-style timezone name lookup doesn't work properly due to a bug in glibc. The workaround is to edit os_lnx.c to include tz_bsd.c instead of tz_sv4.c. Note that other versions of Linux don't support BSD-style timezone name lookup, so don't make this change unless it's needed on your system. . In some systems, the OpenSSL distribution is installed other than at the standard /usr/local/ssl location. If this is the case on your system and you want to build with SSL support, you will need to set the SSLDIR variable, either by including a setting of EXTRASPECIALS in the make command line, e.g. build lnp SPECIALAUTHENTICATORS=ssl EXTRASPECIALS="SSLDIR=/usr/ssl" or by editing .../src/osdep/unix/Makefile . /tmp, /usr/tmp or /var/tmp (if present), and the mail spool directory must be protected 1777 (world write with sticky bit); otherwise mailbox locking and updates won't work. An alternative to 1777 on the mail spool directory is to install the mlock program that is bundled with the IMAP toolkit. . Multiple access protection locking does not work if the mailbox or /tmp are NFS mounted. . Shared access mailbox formats (mbx, mtx, mx, and tenex) do not work well with NFS and such usage is not supported. mmdf and unix formats are supported for use over NFS; however there won't be any multiple access locking protection. . Server startup delays may occur if a reverse DNS (IP address to name) lookup on the client's IP address does not complete in an expeditious fashion. This is actually a DNS problem and should be fixed in the DNS and/or the server's host table. A workaround exists (see the top-level Makefile for details) but is not recommended and can not be used at all with Kerberos. . At the insistance of the security gurus, SSL certification validation is now on by default. This means that you must now use the new /novalidate-cert switch if establishing an SSL connection to a server with a self-signed certificate; i.e. if "imap.example.com" has a self-signed certificate, you must use a mailbox name such as {imap.example.com/ssl/novalidate-cert}INBOX to get an SSL session instead of just {imap.example.com/ssl}INBOX . GCC 8.x and above on SGI systems does not correctly pass/return structures which are smaller than 16 bytes and are not 8 bytes. The problem is that structures are padded at the wrong end; e.g. a 4 byte structure is loaded into the lower 4 bytes of the register when it should be loaded into the upper 4 bytes of the register. This affects IRIX 6 the most because it is a 64-bit system and 4 byte structures are common. This compiler bug impacts the use of inet_ntoa() in c-client and causes syslog messages to show IP addresses as 255.255.255.255 instead of the correct values. The fix is either to use SGI's C compiler instead of GCC or link with an implementation of inet_ntoa() that was built with GCC instead of the standard SGI C library version. . By default, the UNIX SSL build assumes that RSAREF is not needed, because RSA Security Inc. released the RSA public key encryption algorithm into the public domain on September 6, 2000. There is no longer any need to use RSAREF, and since RSAREF is slower than OpenSSL's RSA routines there's good reason not to. If for some reason you still want to use RSAREF, you will need to edit .../src/osdep/unix/Makefile to change SSLRSA to load libRSAglue and librsaref. . By default, the UNIX SSL build assumes that no name conflict exists between OpenSSL and Kerberos 5. If you are using an older version of Kerberos, you may need to edit .../src/osdep/unix/Makefile to change SSLCRYPTO so that it loads the OpenSSL libcrypto library explicitly as libcrypto.a. . By default, host names are canonicalized via gethostbyname() and gethostbyaddr() for everything except for SSL certificate validation. This can represent a security bug due to DNS spoofing, but is more likely to deliver results that users expect and also may be necessary to get Kerberos to work. Set variable "trustdns" in mail.c to NIL if you want to disable this. . Bugs: . It doesn't work to have a "}" character as a user name in /user= in a mailbox name, even if the user name is quoted. In other words, {example.com/user="foo}bar"}zap won't work; foo will be interpreted as an unterminated quoted string and the remote mailbox name will be bar"}zap. . The experimental mx driver has performance problems and shouldn't be used . docs/internal.txt is out of date (again) . UIDPLUS bugs/limitations: . Not supported in all local file formats (see below). . There are two known issues with UIDPLUS in the mmdf and unix formats: (a) If the destination mailbox is currently selected (whether in this or another session), no COPYUID or APPENDUID is returned. The other choice was to assign a UID based upon the uid_last value and hope that the session selecting the mailbox would pick it up and update uid_last. The problem was a timing race if another message was copied/appended to that mailbox before the selecting session updated the mailbox. If the timing race is lost, then all UID in the mailbox would be reassigned by the selecting session, thus making the returned APPENDUID/COPYUID data useless and causing a performance problem. Earlier versions did the "hope for the best" method. This was revoked in favor of not returning COPYUID/APPENDUID. Although this violates RFC 4315, there is a loophole which, although for other purposes, permits this behavior. (b) There is a known failure if the destination mailbox is currently selected by legacy software (e.g. older versions of the IMAP server, Pine, etc.). In this case, all UIDs end up being reassigned by the legacy software. . Annoyances: . Friendly host names (e.g. "server" instead of "server.foo.com") can't be used in a mailbox name with SSL certificate validation; you have to enter the fully-qualified domain name. This is a requirement established by the security gurus. . IMAP client limitations: . No SASL protection mechanisms (SASL authentication mechanisms are supported) . NNTP client limitations: . Non-standard IMAP SCAN extension not supported . POP client limitations: . No SASL protection mechanisms (SASL authentication mechanisms are supported) . No POP3 UID support . Non-standard IMAP SCAN extension not supported . SMTP client limitations: . No SASL protection mechanisms (SASL authentication mechanisms are supported) . No support for use of TURN, ETRN, and pipelining. . No support for enhanced status codes . UNIX limitations: . IPv6 is supported but is not the default on most platforms; you have to use IP=6 in the make command . Supported local file formats: mbx, mh, mmdf, mix, mtx, mx, news, phile, tenex, unix . Supported SASL mechanisms: CRAM-MD5, PLAIN, LOGIN, ANONYMOUS, GSSAPI . Sticky UIDs are not supported in the mh, mtx, and tenex drivers . Creation of keywords is not supported in the mh, mtx, and tenex drivers . Copy and append of keywords only works in the mbx driver. . Flat file formats (mbx, mmdf, mtx, phile, tenex, unix) do not permit mailboxes to have inferior names . SSL temporary key should be seeded better than it is. . UIDPLUS support is limited to the unix, mmdf, mbx, mx, and mix formats. . Non-standard IMAP SCAN extension not support for mh and news formats. . Amiga limitations: . Supported local file formats: mbx, mh, mmdf, mix, mtx, mx, news, phile, tenex, unix . Supported SASL mechanisms: CRAM-MD5, PLAIN, LOGIN, ANONYMOUS . Sticky UIDs are not supported in the mh, mtx, and tenex drivers . Creation of keywords is not supported in the mh, mtx, and tenex drivers . Copy and append of keywords only works in the mbx driver. . Flat file formats (mbx, mmdf, mtx, phile, tenex, unix) do not permit mailboxes to have inferior names . UIDPLUS support is limited to the unix, mmdf, mbx, mx, and mix formats. . Non-standard IMAP SCAN extension not supported for mh and news formats. . Win32 (Win9x/NT/Windows 2000) limitations: . IPv6 is supported in W2K builds but is not the default; you have to use IP=6 in the nmake command . Supported local file formats: mbx, mtx, tenex, unix . Supported SASL mechanisms: CRAM-MD5, PLAIN, LOGIN, ANONYMOUS, GSSAPI . No server SSL or TLS support. . No server authentication for GSSAPI . No server authentication for CRAM-MD5 on NT-based Windows (NT/2K/XP); it does work on DOS-based Windows (9x/Me). . Sticky UIDs are not supported in the mtxnt and tenexnt drivers . Creation of keywords is not supported in the mtxnt and tenexnt drivers . Copy and append of keywords only works in the mbxnt driver. . No support for TCP open timeouts . Flat file formats (mbx, mtx, tenex, unix) do not permit mailboxes to have inferior names . UIDPLUS support is limited to the unix and mbx formats. . Win16 (Win3.1)/DOS limitations: . IPv6 not supported . Supported local file formats: bezerk, mtx . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS . Supported TCPs: B&W, Novell, PC-NFs, PC/TCP, Waterloo, Winsock . Sticky UIDs are not supported on local files . Creation of keywords are not supported on local files . Bezerk driver is read-only and does not handle LF-only newlines well . No support for any TCP timeouts on Waterloo DOS . No support for TCP open timeouts on Winsock and generic DOS . Flat file formats (bezerk, mtx) do not permit mailboxes to have inferior names . Does not work well unless a mailgets routine is armed when fetching texts. . Mac limitations: . IPv6 not supported . No local file drivers . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS . Does not output human-friendly time zone string . TOPS-20 limitations: . IPv6 not supported . No local file drivers . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS . No support for any TCP timeouts . VMS limitations: . IPv6 not supported . No local file drivers . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS . Supported TCPs: Multinet, Netlib . No support for any TCP timeouts on VMS Netlib . No support for TCP open timeouts on VMS Multinet . Time zone must be configured at build time . Does not output human-friendly time zone string . Windows CE limitations: . IPv6 not yet supported . No local file drivers . Supported SASL mechanisms: CRAM-MD5, LOGIN, ANONYMOUS . No support for TCP open timeouts . Not finished, only builds c-client library . OS/2 limitations: . IPv6 not supported . Not finished, does not build locking.txt000064400000045615152527400360006752 0ustar00/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ UNIX Advisory File Locking Implications on c-client Mark Crispin, 28 November 1995 THIS DOCUMENT HAS BEEN UPDATED TO REFLECT THE FACT THAT LINUX SUPPORTS BOTH flock() AND fcntl() AND THAT OSF/1 HAS BEEN BROKEN SO THAT IT ONLY SUPPORTS fcntl(). -- JUNE 15, 2004 THIS DOCUMENT HAS BEEN UPDATED TO REFLECT THE CODE IN THE IMAP-4 TOOLKIT AS OF NOVEMBER 28, 1995. SOME STATEMENTS IN THIS DOCUMENT DO NOT APPLY TO EARLIER VERSIONS OF THE IMAP TOOLKIT. INTRODUCTION Advisory locking is a mechanism by which cooperating processes can signal to each other their usage of a resource and whether or not that usage is critical. It is not a mechanism to protect against processes which do not cooperate in the locking. The most basic form of locking involves a counter. This counter is -1 when the resource is available. If a process wants the lock, it executes an atomic increment-and-test-if-zero. If the value is zero, the process has the lock and can execute the critical code that needs exclusive usage of a resource. When it is finished, it sets the lock back to -1. In C terms: while (++lock) /* try to get lock */ invoke_other_threads (); /* failed, try again */ . . /* critical code here */ . lock = -1; /* release lock */ This particular form of locking appears most commonly in multi-threaded applications such as operating system kernels. It makes several presumptions: (1) it is alright to keep testing the lock (no overflow) (2) the critical resource is single-access only (3) there is shared writeable memory between the two threads (4) the threads can be trusted to release the lock when finished In applications programming on multi-user systems, most commonly the other threads are in an entirely different process, which may even be logged in as a different user. Few operating systems offer shared writeable memory between such processes. A means of communicating this is by use of a file with a mutually agreed upon name. A binary semaphore can be passed by means of the existance or non-existance of that file, provided that there is an atomic means to create a file if and only if that file does not exist. In C terms: /* try to get lock */ while ((fd = open ("lockfile",O_WRONLY|O_CREAT|O_EXCL,0666)) < 0) sleep (1); /* failed, try again */ close (fd); /* got the lock */ . . /* critical code here */ . unlink ("lockfile"); /* release lock */ This form of locking makes fewer presumptions, but it still is guilty of presumptions (2) and (4) above. Presumption (2) limits the ability to have processes sharing a resource in a non-conflicting fashion (e.g. reading from a file). Presumption (4) leads to deadlocks should the process crash while it has a resource locked. Most modern operating systems provide a resource locking system call that has none of these presumptions. In particular, a mechanism is provided for identifying shared locks as opposed to exclusive locks. A shared lock permits other processes to obtain a shared lock, but denies exclusive locks. In other words: current state want shared want exclusive ------------- ----------- -------------- unlocked YES YES locked shared YES NO locked exclusive NO NO Furthermore, the operating system automatically relinquishes all locks held by that process when it terminates. A useful operation is the ability to upgrade a shared lock to exclusive (provided there are no other shared users of the lock) and to downgrade an exclusive lock to shared. It is important that at no time is the lock ever removed; a process upgrading to exclusive must not relenquish its shared lock. Most commonly, the resources being locked are files. Shared locks are particularly important with files; multiple simultaneous processes can read from a file, but only one can safely write at a time. Some writes may be safer than others; an append to the end of the file is safer than changing existing file data. In turn, changing a file record in place is safer than rewriting the file with an entirely different structure. FILE LOCKING ON UNIX In the oldest versions of UNIX, the use of a semaphore lockfile was the only available form of locking. Advisory locking system calls were not added to UNIX until after the BSD vs. System V split. Both of these system calls deal with file resources only. Most systems only have one or the other form of locking. AIX and newer versions of OSF/1 emulate the BSD form of locking as a jacket into the System V form. Ultrix and Linux implement both forms. BSD BSD added the flock() system call. It offers capabilities to acquire shared lock, acquire exclusive lock, and unlock. Optionally, the process can request an immediate error return instead of blocking when the lock is unavailable. FLOCK() BUGS flock() advertises that it permits upgrading of shared locks to exclusive and downgrading of exclusive locks to shared, but it does so by releasing the former lock and then trying to acquire the new lock. This creates a window of vulnerability in which another process can grab the exclusive lock. Therefore, this capability is not useful, although many programmers have been deluded by incautious reading of the flock() man page to believe otherwise. This problem can be programmed around, once the programmer is aware of it. flock() always returns as if it succeeded on NFS files, when in fact it is a no-op. There is no way around this. Leaving aside these two problems, flock() works remarkably well, and has shown itself to be robust and trustworthy. SYSTEM V/POSIX System V added new functions to the fnctl() system call, and a simple interface through the lockf() subroutine. This was subsequently included in POSIX. Both offer the facility to apply the lock to a particular region of the file instead of to the entire file. lockf() only supports exclusive locks, and calls fcntl() internally; hence it won't be discussed further. Functionally, fcntl() locking is a superset of flock(); it is possible to implement a flock() emulator using fcntl(), with one minor exception: it is not possible to acquire an exclusive lock if the file is not open for write. The fcntl() locking functions are: query lock station of a file region, lock/unlock a region, and lock/unlock a region and block until have the lock. The locks may be shared or exclusive. By means of the statd and lockd daemons, fcntl() locking is available on NFS files. When statd is started at system boot, it reads its /etc/state file (which contains the number of times it has been invoked) and /etc/sm directory (which contains a list of all remote sites which are client or server locking with this site), and notifies the statd on each of these systems that it has been restarted. Each statd then notifies the local lockd of the restart of that system. lockd receives fcntl() requests for NFS files. It communicates with the lockd at the server and requests it to apply the lock, and with the statd to request it for notification when the server goes down. It blocks until all these requests are completed. There is quite a mythos about fcntl() locking. One religion holds that fcntl() locking is the best thing since sliced bread, and that programs which use flock() should be converted to fcntl() so that NFS locking will work. However, as noted above, very few systems support both calls, so such an exercise is pointless except on Ultrix and Linux. Another religion, which I adhere to, has the opposite viewpoint. FCNTL() BUGS For all of the hairy code to do individual section locking of a file, it's clear that the designers of fcntl() locking never considered some very basic locking operations. It's as if all they knew about locking they got out of some CS textbook with not investigation of real-world needs. It is not possible to acquire an exclusive lock unless the file is open for write. You could have append with shared read, and thus you could have a case in which a read-only access may need to go exclusive. This problem can be programmed around once the programmer is aware of it. If the file is opened on another file designator in the same process, the file is unlocked even if no attempt is made to do any form of locking on the second designator. This is a very bad bug. It means that an application must keep track of all the files that it has opened and locked. If there is no statd/lockd on the NFS server, fcntl() will hang forever waiting for them to appear. This is a bad bug. It means that any attempt to lock on a server that doesn't run these daemons will hang. There is no way for an application to request flock() style ``try to lock, but no-op if the mechanism ain't there''. There is a rumor to the effect that fcntl() will hang forever on local files too if there is no local statd/lockd. These daemons are running on mailer.u, although they appear not to have much CPU time. A useful experiment would be to kill them and see if imapd is affected in any way, but I decline to do so without an OK from UCS! ;-) If killing statd/lockd can be done without breaking fcntl() on local files, this would become one of the primary means of dealing with this problem. The statd and lockd daemons have quite a reputation for extreme fragility. There have been numerous reports about the locking mechanism being wedged on a systemwide or even clusterwide basis, requiring a reboot to clear. It is rumored that this wedge, once it happens, also blocks local locking. Presumably killing and restarting statd would suffice to clear the wedge, but I haven't verified this. There appears to be a limit to how many locks may be in use at a time on the system, although the documentation only mentions it in passing. On some of their systems, UCS has increased lockd's ``size of the socket buffer'', whatever that means. C-CLIENT USAGE c-client uses flock(). On System V systems, flock() is simulated by an emulator that calls fcntl(). BEZERK AND MMDF Locking in the traditional UNIX formats was largely dictated by the status quo in other applications; however, additional protection is added against inadvertantly running multiple instances of a c-client application on the same mail file. (1) c-client attempts to create a .lock file (mail file name with ``.lock'' appended) whenever it reads from, or writes to, the mail file. This is an exclusive lock, and is held only for short periods of time while c-client is actually doing the I/O. There is a 5-minute timeout for this lock, after which it is broken on the presumption that it is a stale lock. If it can not create the .lock file due to an EACCES (protection failure) error, it once silently proceeded without this lock; this was for systems which protect /usr/spool/mail from unprivileged processes creating files. Today, c-client reports an error unless it is built otherwise. The purpose of this lock is to prevent against unfavorable interactions with mail delivery. (2) c-client applies a shared flock() to the mail file whenever it reads from the mail file, and an exclusive flock() whenever it writes to the mail file. This lock is freed as soon as it finishes reading. The purpose of this lock is to prevent against unfavorable interactions with mail delivery. (3) c-client applies an exclusive flock() to a file on /tmp (whose name represents the device and inode number of the file) when it opens the mail file. This lock is maintained throughout the session, although c-client has a feature (called ``kiss of death'') which permits c-client to forcibly and irreversibly seize the lock from a cooperating c-client application that surrenders the lock on demand. The purpose of this lock is to prevent against unfavorable interactions with other instances of c-client (rewriting the mail file). Mail delivery daemons use lock (1), (2), or both. Lock (1) works over NFS; lock (2) is the only one that works on sites that protect /usr/spool/mail against unprivileged file creation. Prudent mail delivery daemons use both forms of locking, and of course so does c-client. If only lock (2) is used, then multiple processes can read from the mail file simultaneously, although in real life this doesn't really change things. The normal state of locks (1) and (2) is unlocked except for very brief periods. TENEX AND MTX The design of the locking mechanism of these formats was motivated by a design to enable multiple simultaneous read/write access. It is almost the reverse of how locking works with bezerk/mmdf. (1) c-client applies a shared flock() to the mail file when it opens the mail file. It upgrades this lock to exclusive whenever it tries to expunge the mail file. Because of the flock() bug that upgrading a lock actually releases it, it will not do so until it has acquired an exclusive lock (2) first. The purpose of this lock is to prevent against expunge taking place while some other c-client has the mail file open (and thus knows where all the messages are). (2) c-client applies a shared flock() to a file on /tmp (whose name represents the device and inode number of the file) when it parses the mail file. It applies an exclusive flock() to this file when it appends new mail to the mail file, as well as before it attempts to upgrade lock (1) to exclusive. The purpose of this lock is to prevent against data being appended while some other c-client is parsing mail in the file (to prevent reading of incomplete messages). It also protects against the lock-releasing timing race on lock (1). OBSERVATIONS In a perfect world, locking works. You are protected against unfavorable interactions with the mailer and against your own mistake by running more than one instance of your mail reader. In tenex/mtx formats, you have the additional benefit that multiple simultaneous read/write access works, with the sole restriction being that you can't expunge if there are any sharers of the mail file. If the mail file is NFS-mounted, then flock() locking is a silent no-op. This is the way BSD implements flock(), and c-client's emulation of flock() through fcntl() tests for NFS files and duplicates this functionality. There is no locking protection for tenex/mtx mail files at all, and only protection against the mailer for bezerk/mmdf mail files. This has been the accepted state of affairs on UNIX for many sad years. If you can not create .lock files, it should not affect locking, since the flock() locks suffice for all protection. This is, however, not true if the mailer does not check for flock() locking, or if the the mail file is NFS-mounted. What this means is that there is *no* locking protection at all in the case of a client using an NFS-mounted /usr/spool/mail that does not permit file creation by unprivileged programs. It is impossible, under these circumstances, for an unprivileged program to do anything about it. Worse, if EACCES errors on .lock file creation are no-op'ed , the user won't even know about it. This is arguably a site configuration error. The problem with not being able to create .lock files exists on System V as well, but the failure modes for flock() -- which is implemented via fcntl() -- are different. On System V, if the mail file is NFS-mounted and either the client or the server lacks a functioning statd/lockd pair, then the lock attempt would have hung forever if it weren't for the fact that c-client tests for NFS and no-ops the flock() emulator in this case. Systemwide or clusterwide failures of statd/lockd have been known to occur which cause all locks in all processes to hang (including local?). Without the special NFS test made by c-client, there would be no way to request BSD-style no-op behavior, nor is there any way to determine that this is happening other than the system being hung. The additional locking introduced by c-client was shown to cause much more stress on the System V locking mechanism than has traditionally been placed upon it. If it was stressed too far, all hell broke loose. Fortunately, this is now past history. TRADEOFFS c-client based applications have a reasonable chance of winning as long as you don't use NFS for remote access to mail files. That's what IMAP is for, after all. It is, however, very important to realize that you can *not* use the lock-upgrade feature by itself because it releases the lock as an interim step -- you need to have lock-upgrading guarded by another lock. If you have the misfortune of using System V, you are likely to run into problems sooner or later having to do with statd/lockd. You basically end up with one of three unsatisfactory choices: 1) Grit your teeth and live with it. 2) Try to make it work: a) avoid NFS access so as not to stress statd/lockd. b) try to understand the code in statd/lockd and hack it to be more robust. c) hunt out the system limit of locks, if there is one, and increase it. Figure on at least two locks per simultaneous imapd process and four locks per Pine process. Better yet, make the limit be 10 times the maximum number of processes. d) increase the socket buffer (-S switch to lockd) if it is offered. I don't know what this actually does, but giving lockd more resources to do its work can't hurt. Maybe. 3) Decide that it can't possibly work, and turn off the fcntl() calls in your program. 4) If nuking statd/lockd can be done without breaking local locking, then do so. This would make SVR4 have the same limitations as BSD locking, with a couple of additional bugs. 5) Check for NFS, and don't do the fcntl() in the NFS case. This is what c-client does. Note that if you are going to use NFS to access files on a server which does not have statd/lockd running, your only choice is (3), (4), or (5). Here again, IMAP can bail you out. These problems aren't unique to c-client applications; they have also been reported with Elm, Mediamail, and other email tools. Of the other two SVR4 locking bugs: Programmer awareness is necessary to deal with the bug that you can not get an exclusive lock unless the file is open for write. I believe that c-client has fixed all of these cases. The problem about opening a second designator smashing any current locks on the file has not been addressed satisfactorily yet. This is not an easy problem to deal with, especially in c-client which really doesn't know what other files/streams may be open by Pine. Aren't you so happy that you bought an System V system? internal.txt000064400000340601152527400360007131 0ustar00/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ Documentation of c-client Functions and Interfaces REVISED: 19 August 1996 Credits The original version of this document was written by Mark Crispin at the University of Washington, and described the version of c-client that supported the IMAP2 (RFC 1176) and IMAP2bis (unpublished) protocols. This version is a substantial rewrite of that document, and was written by Mark Crispin with funding from Sun Microsystems, Incorporated. Sun's generous support of this work is gratefully acknowledged. Road Map This document is organized into the following sections. Except as noted, an implementor of an application that uses c-client needs to be familiar with all of these sections. Someone who plans to write a new mailbox driver for c-client (or otherwise modify it) needs to be familiar with all sections, no exception. History History of how c-client came about. Overview Read this before designing an application that uses c-client. c-client Structures Documentation of several important c-client structs which are used in, and returned by, c-client calls. String Structures Documentation of the concept of a "string structure", which provides random access to strings without requiring that the string be in memory. c-client Support Functions Documentation of support functions for c-client; these deal with c-client functionality. Only mail_parameters() is of interest to most application developers. Advanced application developers, particularly for limited memory systems, may also need to know about the readfn_t, mailgets_t, mailcache_t, and tcptimeout_t function pointer types, and possibly also the mail_valid_net_parse() function. Mailbox Access Functions Documentation of functions which deal with mailboxes; listing, subscribing, creating, deleting, renaming, status inquiries, opening, and closing mailboxes. Handle Functions Documentation of mail stream handles, which provide protection for an advanced application which may have multiple pointers to a single mail stream. If a stream has a handle on it, closing the stream does not release its memory, so pointers to it in the application remain valid. Freeing the last handle will free the entire stream. This is only of interest for advanced application developers. Message Data Fetching Functions Documentation on message data fetching in an open mailbox, including parsed representations of RFC-822 and MIME headers and message text. Also how to fetch message attributes (flags, internal date, sizes). Message Status Manipulation Functions Documentation on altering message flags in an open mailbox. Mailbox Searching Documentation on searching an open mailbox for messages which match certain criteria (e.g. "messages sent July 4 from Jones with text `Paris'"). Miscellaneous Mailbox and Message Functions Documentation on other operations that would be used by an application but that don't fit into any of the above categories. Date/Time Handling Functions Documentation on functions that deal with date/time strings. This is only of interest for advanced application developers and for implementors of new c-client drivers. Utility Functions Documentation on internal utility functions. This is primarily of interest for implementors of new c-client drivers, but advanced application developers may also use some of these functions. Data Structure Instantiation/Destruction functions Documentation on creating and destroy c-client structures. This is primarily of interest for implementors of new c-client drivers. However, application developers will need some of these functions to create and destroy structures which are used as arguments to various application functions. Authentication Functions Documentation on support for network protocol authentication functions. This is only of interest for implementors of new c-client drivers which deal with authentication mechanisms. Network Access Functions Documentation on creating and destroy c-client structures. This is primarily of interest for implementors of new c-client drivers which deal with a network. However, advanced application developers may need to use this information if they wish to insert their own layer into a network session. Subscription Management Functions Documentation on managing the local (client-based) subscription database file. This is primarily of interest to advanced application developers. Miscellaneous Utility Functions Documentation on various useful utility functions, such as "make a copy of this string." SMTP Functions Documentation on posting email messages via SMTP protocol. NNTP Functions Documentation on posting netnews messages via NNTP protocol. RFC 822 Support Functions Documentation on public RFC-822/MIME functions. This is primarily of interest for implementors of new c-client drivers and advanced application developers. Operating System-Dependent Public Interface Documentation on OS-dependent functions. With the exception of fs_get(), fs_give(), and fs_resize(), which should be called instead of malloc(), free(), and realloc(), these functions are primarily of interest for implementors of new c-client drivers. Main Program Callbacks Documentation of functions which the main program must provide as callbacks from c-client. Driver Interface Documentation of the driver dispatch vector and the functions which a driver must supply. This is primarily of interest for implementors of new c-client drivers. Driver Support Functions Documentation of support functions which are called by drivers. This is primarily of interest for implementors of new c-client drivers. History The c-client API was originally written by Mark Crispin at Stanford University as a set of routines to support IMAP and SMTP from a main program which would handle the user interface. In its original form, it was written as the low-level routines that were to be used as part of a Macintosh client. The first IMAP client, MM-D (for "MM on Xerox D machines" -- MM was a popular DEC-20 mail program) was written in Interlisp for Xerox Lisp machines. At that time, there was no name for the embryonic Mac client, but since it was the first one to be written in C instead of Lisp, it was given a development name of "C client". This name became "c-client" because that is the name of the subdirectory on UNIX where the source files were stored. To exercise the routines, a minimal main program which uses c-client, mtest, was written. mtest has subsequently been extended so that it runs on every platform that c-client is ported. The real Mac client, was eventually written by Frank Gilmurrary and Bill Yeager at Stanford using the autumn 1988 version of c-client and named "MacMS". In the winter of 1988-89, Mark Crispin, who had changed jobs to the University of Washington, developed MS as an MM-like text-based program for UNIX and MailManager as a GUI-based program for NeXT machines. The realization sunk in that this API needed its own name. As early as spring 1989, there were at least four programs (mtest, MS, MailManager, and MacMS) that used it. The name c-client thus became permanent. In its history, c-client has undergone two major redesigns, both by Mark Crispin who is now on the staff at the University of Washington. The first major redesign added the following: 1) ANSI C calling conventions throughout to assist in function argument type checking. 2) Vectoring mail access calls through "driver" methods; thus providing transparent access to multiple types of mail stores with the same call. 3) MIME support. The second major redesign was part of the IMAP4 project. Many c-client functions were extended with additional arguments and options. The driver interface was also made simpler, with more work done by driver-independent code. Overview The most important file for the author of an application using the c-client is mail.h. mail.h defines several important structures of data which are passed between the main program and the c-client. Although some functions (e.g. mail_fetchtext_body()) return the data fetched, for certain other data items (e.g. flags) you need to get the data as a structure reference. mail.h also defines a large number of useful constants and structures. When a function in mail.h exists to reference data, it MUST be used instead of referencing the structures directly. This is because in some cases the data is not actually fetched until a reference (via the function call) is made. For example, although the MESSAGECACHE element for a message can be obtained by indexing the proper cache element in the stream, there is no guarantee that the item in fact exists unless mail_fetchstructure_full() is called for that message. Less costly functions. also exist to create and load a MESSAGECACHE element. The main program will probably also need to include smtp.h, misc.h, and osdep.h, but this usage should be solely to receive function prototypes. Any other definitions in those files should be considered private to that module. Two important predefined symbols are NIL and T. NIL is any sort of "false"; T is any sort of "true". NIL is also used to null-specify certain optional arguments. * * * IMPORTANT * * * Any multi-threaded application should test stream->lock prior to calling any c-client stream functions. Any attempt to call a mail_xxx() function while one is already in progress on the same stream will cause the application to fail in unpredictable ways. Note that this check is insufficient in a preemptive-scheduling multi-tasking application due to the possibility of a timing race. Such applications must be written so that only one process accesses the stream, or to have a higher level lock. Since MAIL operations will not finish until they are completed, a single-tasking application does not have to worry about this problem, except in the callback invoked from MAIL (e.g. mm_exists(), etc.) in which case the stream is *always* locked. c-client Structures c-client has a large number of structures which are used for multiple functions. The most important of these are described here. The MAILSTREAM structure is used to reference open mailboxes. Applications may reference the following: char *mailbox; mailbox name unsigned short use; stream use count, this is incremented unsigned short sequence; stream sequence, this is incremented each time a stream is reused (i.e. mail_open() is called to open a different mailbox on this stream) unsigned int rdonly : 1; stream is open read-only unsigned int anonymous : 1; stream is open with anonymous access unsigned int halfopen : 1; stream is half-open; it can be reopened or used for functions that don't need a open mailbox such as mail_create() but no message data can be fetched unsigned int perm_seen : 1; Seen flag can be set permanently unsigned int perm_deleted : 1; Deleted flag can be set permanently unsigned int perm_flagged : 1; Flagged flag can be set permanently unsigned int perm_answered :1; Answered flag can be set permanently unsigned int perm_draft : 1; Draft flag can be set permanently unsigned int kwd_create : 1; new user flags can be created by referencing then in mail_setflag() or mail_clearflag(). Note: this can change during a session (e.g. if there is a limit on the number of keywords), so check after creating a new flag to see if any more can be created before letting the user try to do so unsigned long perm_user_flags; corresponding user flags can be set permanently. This is a bit mask which matches the entries in stream->user_flags[] unsigned long gensym; generated unique value. Always referenced with stream->gensys++ unsigned long nmsgs; number of messages in current mailbox unsigned long recent; number of recent messages in current mailbox unsigned long uid_validity; UID validity value; this is used to verify that recorded UIDs match the UIDs that the stream has. If the mailbox does not have matching UIDs (e.g. the UIDs were lost or not recorded) then the UID validity value will be different unsigned long uid_last; highest currently assigned UID in the current mailbox; a new UID will be assigned with ++stream->uid_last char *user_flags[NUSERFLAGS]; pointers to user flag names in bit order from stream->perm_user_flags or elt->user_flags The following MAILSTREAM values are only used internally: DRIVER *dtb; dispatch table for this driver void *local; pointer to driver local data unsigned int lock : 1; stream lock flag (an operation is in progress; used as a bug trap to detect recursion back to c-client from callback routines). unsigned int debug : 1; debugging information should be logged via mm_dlog(). unsigned int silent : 1; don't do main program callbacks on this stream (used when a stream is opened internally) unsigned int scache : 1; short caching; don't cache information in memory The following MAILSTREAM values are only used by the cache manager routine (see the documentation about mailcache_t above): unsigned long cachesize; size of c-client message cache union { void **c; to get at the cache in general MESSAGECACHE **s; message cache array LONGCACHE **l; long cache array } cache; The following MAILSTREAM values are for the convenience of drivers that use short caching and want to be able to garbage collect any values that they returned: unsigned long msgno; message number of `current' message ENVELOPE *env; pointer to `current' message envelope BODY *body; pointer to `current' message body char *text; pointer to `current' text The MESSAGECACHE structure (commonly called an "elt" as a nickname for "cache ELemenT") contains information about messages. Applications may use the following: unsigned long msgno; message number. If the elt is locked (by elt->lockcount++), then the elt pointer can be stored (e.g. with the data for a window which draws this message) and elt->msgno will change automatically whenever expunges are done so the window will always view the correct message. If elt->msgno becomes 0, then the message has been expunged, but the elt won't be freed until the elt lock count is decremented (by mail_free_elt()). unsigned long uid; message unique ID unsigned int hours: 5; internal date hours (0-23) unsigned int minutes: 6; internal date minutes (0-59) unsigned int seconds: 6; internal date seconds (0-59) unsigned int zoccident : 1; non-zero if internal date time zone is west of UTC unsigned int zhours : 4; internal date time zone hours from UTC (0-12) unsigned int zminutes: 6; internal date time zone minutes (0-59) unsigned int seen : 1; message Seen flag unsigned int deleted : 1; message Deleted flag unsigned int flagged : 1; message Flagged flag unsigned int answered : 1; message Answered glag unsigned int draft : 1; message Draft flag unsigned int valid : 1; flags are valid in this elt; an elt that was newly created but never loaded with flags won't have this set. unsigned int recent : 1; message recent flag unsigned int searched : 1; message matches search criteria in most recent mail_search_full() call unsigned int spare : 1; reserved for application use unsigned int spare2 : 1; reserved for application use unsigned int spare3 : 1; reserved for application use unsigned int lockcount : 8; non-zero if multiple references to this elt. Refer to the msgno member for more information. unsigned int day : 5; internal date day of month (1-31) unsigned int month : 4; internal date month of year (1-12) unsigned int year : 7; internal date year since BASEYEAR (currently 1970; was 1969 in older versions so use BASEYEAR instead of having the base year wired in) unsigned long user_flags; message user flags; this is a bit mask which matches the entries in stream->user_flags[] unsigned long rfc822_size; size of message in octets The following MESSAGECACHE values are only used internally by drivers: unsigned int sequence : 1; message is in sequence from either mail_sequence() or mail_uid_sequence() unsigned long data1; first data item unsigned long data2; second data item unsigned long data3; third data item unsigned long data4; fourth data item The ADDRESS structure is a parsed form of a linked list of RFC 822 addresses. It contains the following information: char *personal; personal name phrase char *adl; at-domain-list (also called "source route") char *mailbox; mailbox name char *host; domain name of mailbox's host char *error; error in address from smtp_mail(); if an error is returned from smtp_mail() for one of the recipient addresses the SMTP server's error text for that recipient can be found here. If it is null then there was no error (or an error was found with a prior recipient ADDRESS *next; pointer to next address in list The ENVELOPE structure is a parsed form of the RFC 822 header. Its member names correspond to the RFC 822 field names. It contains the following information: char *remail; remail header if any ADDRESS *return_path; error return address char *date; message composition date string ADDRESS *from; from address list ADDRESS *sender; sender address list ADDRESS *reply_to; reply address list char *subject; message subject string ADDRESS *to; primary recipient list ADDRESS *cc; secondary recipient list ADDRESS *bcc; blind secondary recipient list char *in_reply_to; replied message ID char *message_id; message ID char *newsgroups; USENET newsgroups char *followup_to; USENET reply newsgroups char *references; USENET references The BODY structure is a parsed form of a linked list of the MIME structure of a message. It contains the following information. unsigned short type; body primary type code. This is an index into the body_types vector of body type names. The following body types are pre-defined: TYPETEXT unformatted text TYPEMULTIPART multiple part TYPEMESSAGE encapsulated message TYPEAPPLICATION application data TYPEAUDIO audio TYPEIMAGE static image (GIF, JPEG, etc.) TYPEVIDEO video TYPEOTHER unknown Additional types up to TYPEMAX are dynamically defined if they are encountered by c-client. unsigned short encoding; body transfer encoding. This is an index into the body_encodings vector of body encoding names. The following body encodings are pre-defined: ENC7BIT 7 bit SMTP semantic data ENC8BIT 8 bit SMTP semantic data ENCBINARY 8 bit binary data ENCBASE64 base-64 encoded data ENCQUOTEDPRINTABLE human-readable 8-as-7 bit data ENCOTHER unknown Additional encodings up to ENCMAX are dynamically defined if they are encountered by c-client. char *subtype; body subtype string PARAMETER *parameter; parameter list char *id; body content identifier char *description; body content description unsigned char *contents.text; when composing a message that is NOT of TYPEMULTIPART, non-binary text of the content is stored here. Note that this happens even when the text is of TYPEMESSAGE. Text of encoding ENC8BIT may be converted to ENCQUOTEDPRINTABLE when it is sent. This should not be referenced for any other reason; in particular, this is NOT the way for an application to access content data (use mail_fetchbody_full() instead). BINARY *contents.binary; when composing a message that is NOT of TYPEMULTIPART, binary content (of encoding ENCBINARY) is stored here. It will be converted to ENCBASE64 when it is sent. This should not be referenced for any other reason; in particular, this is NOT the way for an application to access content data (use mail_fetchbody_full() instead). PART *contents.part; for body parts of TYPEMULTIPART, this contains the list of body parts in this multipart MESSAGE contents.msg; for body parts of TYPEMESSAGE with subtype "RFC822", this contains the encapsulated message unsigned long size.lines; size in lines unsigned long size.bytes; size in octets. This MUST be set when composing a message if the encoding is ENC8BIT or ENCBINARY. char *md5; body content MD5 checksum The following BODY information is used only by c-client internally. The use of this data is driver-specific and it can not be relied-upon by applications. unsigned char *contents.text; drivers can store a pointer to the body contents as text here. unsigned long size.ibytes; internal size of the body content (prior to newline conversion, etc.) in octets The MESSAGE structure is a parsed form of a MESSAGE/RFC822 MIME body part. It contains the following information: ENVELOPE *env; encapsulated message RFC 822 header BODY *body; encapsulated message MIME structure The following MESSAGE information is used only by c-client internally. The use of this data is driver-specific and it can not be relied-upon by applications. char *hdr; encapsulated message header unsigned long hdrsize; message header size char *text; message in RFC 822 form unsigned long offset; offset of text from header The PARAMETER structure is a parsed form of a linked list of attribute/value pairs. It contains the following information: char *attribute; attribute name char *value; value PARAMETER *next; next parameter in list The PART structure is a parsed form of a linked list of MIME body parts. It contains the following information: BODY body; body information for this part PART *next; next body part The following PART information is used only by c-client internally. The use of this data is driver-specific and it can not be relied-upon by applications. unsigned long offset; offset from body origin The NETMBX structure is a parsed form of a network mailbox name: char host[NETMAXHOST]; remote host name char user[NETMAXUSER]; remote user name if specified char mailbox[NETMAXMBX]; remote mailbox name char service[NETMAXSRV]; remote service name (IMAP4, NNTP, etc.) unsigned long port; TCP/IP port number if specified unsigned int anoflag : 1; anonymous access requested unsigned int dbgflag : 1; protocol debugging telemetry, via mm_dlog(), requested The STRINGLIST structure is a list of strings (which may have embedded NULs) and their lengths: char *text; string text unsigned long size; string length STRINGLIST *next; next string in list String Structures A string structure is analogous to a char*, and is used in some functions as an input argument. It represents a string of data in a way that does not necessarily require the entire string to be in memory at once. This is essential for small machines with highly-restricted memory limits (e.g. DOS). String Structure Access To use a string structure, the caller needs to know a string driver and needs to know the driver-dependent data used by that string structure. A simple string driver is mail_string, a string driver that takes an in-memory char* string as the driver-dependent data. The DOS port uses string drivers that take a struct holding a file descriptor and a file offset. Often the user of a string driver is the same module that defined it, so usually the programmer knows about its conventions. The following calls are used to access a string structure: void INIT (STRING *s,STRINGDRIVER *d,void *data,unsigned long size); s pointer to the string structure to be initialized d pointer to the string driver data pointer to driver-dependent data, from which the driver can determine string data size size of the string This call initializes the string stucture. unsigned long SIZE (STRING *s); s pointer to the string structure This call returns the number of characters remaining in the string after the current string character pointer. char CHR (STRING *s); s pointer to the string structure This call returns the character at the current string character pointer. char SNX (STRING *s); s pointer to the string structure This call returns the character at the current string character pointer, and increments the string character pointer. unsigned long GETPOS (STRING *s); s pointer to the string structure This returns the value of the current string character pointer. void SETPOS (STRING *s,unsigned long i); s pointer to the string structure i new string pointer value This method sets the string character pointer to the given value. String Structure Internals A string structure holds the following data: void *data; used by the string driver as it likes unsigned long data1; used by the string driver as it likes unsigned long size; static, holds the total length of the string from the INIT call char *chunk; current chunk of in-memory data; this is used for buffering to avoid unnecessary calls to the string driver's next method. unsigned long chunksize; size of an in-memory data chunk unsigned long offset; position of first character of the chunk in the overall string char *curpos; current position; this is what CHR() will access unsigned long cursize; number of characters remaining in the current string STRINGDRIVER *dtb; the string driver for this string structure A string structure is manipulated by a string driver, which has the following access methods: void (*init) (STRING *s,void *data,unsigned long size); s pointer to the string structure to be initialized data pointer to driver-dependent data, from which the driver can determine string data size size of the string This method initializes the string stucture. It can use the data, data1, and chunksize values as it likes. The remaining values must be set up as follows: size static, copied from the size argument chunk pointer to a buffer loaded with initial data chunksize size of the buffer offset 0 curpos copied from chunk cursize copied from chunksize dtb STRINGDRIVER identity pointer char (*next) (STRING *s); s pointer to the string structure This method returns the character at the current string character pointer, and increments the string character pointer. This method is likely to call the setpos method if the desired character is not in the current chunk. void (*setpos) (STRING *s,unsigned long i); s pointer to the string structure i new string pointer value This method sets the string character pointer to the given value. If the pointer is not in the current chunk, then a new chunk is loaded and the associated values (chunk, offset, curpos, cursize) are adjusted accordingly. c-client Support Functions void mail_string_init (STRING *s,void *data,unsigned long size); char mail_string_next (STRING *s); void mail_string_setpos (STRING *s,unsigned long i); These three functions are the init, next, and setpos string structure access methods for the build-in mail_string string driver. mail_string is a basic string driver for a char* string. See the documentation below on "String Structures" for more information. void mail_link (DRIVER *driver); driver pointer to the driver to be added This function adds the specified driver to the list of mailbox drivers. Initially there are no drivers lunk, so all programs which intend to use c-client need to have at least one call to this function. A function which uses IMAP4 would have a statement such as: mail_link (&imapdriver); /* link in IMAP driver */ early in the program's initialization. Normally, this is done by the statement #include "linkage.c" which will include the "system standard driver linkage" defined when c-client was built. By using linkage.c instead of explicit mail_link() calls, you are guaranteed that you will have a consistant linkage among all software built on this system. void auth_link (AUTHENTICATOR *auth); auth pointer to the authenticator to be added This function adds the specified authenticator to the list of authenticators. Initially there are no authenticators lunk. Normally, this is done by linkage.c so you don't need to call this routine explicitly. void *mail_parameters (MAILSTREAM *stream,long function,void *value); stream stream to poll or NIL function function code value new value for function codes that change a parameter This function fetches or changes the settings of various c-client operational parameters depending upon the function. If the stream is specified, only the action for the underlying driver for that stream is taken; however, the scope of the operational parameters is global so there is generally no reason for the stream argument ever to be non-NIL. The function codes ENABLE_DRIVER and DISABLE_DRIVER take a driver pointer as a value. These functions enable and disable mailbox processing by that driver. By default, all drivers are enabled. The remaining function codes are in a pair named GET_xxx to fetch an operational parameter and SET_xxx to set the parameter: GET_DRIVERS / SET_DRIVERS The list of currently lunk drivers. GET_GETS / SET_GETS If non-NIL, points to a function for reading message text. Defaults to NIL. This function is called with three arguments; a function pointer to a "reading function", a stream for the reading function, and a size in octets. The reading function is in turn called with the stream, a size in octets, and a pointer to a readin buffer. This function returns with a char* string, which will be returned by the mail_fetchheader(), mail_fetchtext(), or mail_fetchbody() function which triggered the message text reading. The purpose is to permit reading of large strings, without requiring an in-memory buffer for the entire string. The idea is that this function can store the data in some form other than a char* (e.g. a temporary file) and the main program will recognize that it should get the text from there instead of from the results from mail_fetch....(). This is only supported on DOS and Win16; on other platforms it is inconsistent whether or not it works. GET_CACHE / SET_CACHE Points to the c-client cache manager function. Defaults to mm_cache(). GET_SMTPVERBOSE / SET_SMTPVERBOSE If non-NIL, points to a function that accepts a char* string. This function is called any time the SMTP routines receive a response code less than 100. The argument is the text of the response code GET_RFC822OUTPUT / SET_RFC822OUTPUT If non-NIL, points to an alternate rfc822_output() function. rfc822_output() will call this function and return instead of doing its normal action. See the description of rfc822_output() for more information. GET_USERNAME / SET_USERNAME The logged-in user name. GET_HOMEDIR / SET_HOMEDIR The home directory path name. GET_LOCALHOST / SET_LOCALHOST The local host name. GET_SYSINBOX / SET_SYSINBOX The "system INBOX" (where mail is delivered) path name. GET_OPENTIMEOUT / SET_OPENTIMEOUT TCP/IP open timeout in seconds. Defaults to 0 (system default timeout, usually 75 seconds on Unix). GET_READTIMEOUT / SET_READTIMEOUT TCP/IP read timeout in seconds. Defaults to 0 (no timeout). GET_WRITETIMEOUT / SET_WRITETIMEOUT TCP/IP write timeout in seconds. Defaults to 0 (no timeout). GET_CLOSETIMEOUT / SET_CLOSETIMEOUT TCP/IP close timeout in seconds. Defaults to 0 (no timeout). GET_TIMEOUT / SET_TIMEOUT If non-NIL, points to the function called when a TCP/IP timeout occurs. This function is called with the number of seconds since the start of the TCP operation. If it returns non-zero, the TCP/IP operation is continued; if it returns non-zero, the TCP/IP connection is aborted. GET_RSHTIMEOUT / SET_RSHTIMEOUT rsh connection timeout in seconds. Defaults to 15 seconds. GET_MAXLOGINTRIALS / SET_MAXLOGINTRIALS The maximum number of login attempts permitted in an IMAP or POP connection. Defaults to 3. GET_LOOKAHEAD / SET_LOOKAHEAD The number of subsequent envelopes prefetched in IMAP when an envelope is fetched. Defaults to 20. GET_IMAPPORT / SET_IMAPPORT The IMAP port number. Defaults to 143. GET_PREFETCH / SET_PREFETCH The number of envelopes prefetched in IMAP from the results of a SEARCH. Defaults to 20. GET_CLOSEONERROR / SET_CLOSEONERROR If non-NIL, close an opening IMAP connection if the SELECT command fails instead of returning a half-open stream. Defaults to NIL. GET_POP3PORT / SET_POP3PORT The POP3 port number. Defaults to 110. GET_UIDLOOKAHEAD / SET_UIDLOOKAHEAD The number of UIDs premapped when a message number is translated to a UID. Defaults to 1000. GET_MBXPROTECTION / SET_MBXPROTECTION Default file protection for newly created mailboxes. Defaults to 0600. GET_DIRPROTECTION / SET_DIRPROTECTION Default file protection for newly created directories. Defaults to 0700. GET_LOCKPROTECTION / SET_LOCKPROTECTION Default file protection for locks. Defaults to 0666. WARNING: don't blithely change this. If other processes can't get access to a lock then they will have trouble in locking properly. GET_FROMWIDGET / SET_FROMWIDGET If non-NIL, APPEND in the Unix mbox format will insert a ">" character in front of all lines which begin with the string "From ". If NIL, it will only do so if the entire line looks like a message delimiter (that is, the date is also in correct format). Defaults to T. GET_NEWSACTIVE / SET_NEWSACTIVE Netnews active file path name. GET_NEWSSPOOL / SET_NEWSSPOOL Netnews spool directory path name. GET_NEWSRC / SET_NEWSRC Netnews newsgroup reading status file (.newsrc) path name. GET_EXTENSION / SET_EXTENSION If non-NIL, points to a string holding the extension for all mailbox files. This is only supported on DOS and Win16. GET_DISABLEFCNTLLOCK / SET_DISABLEFCNTLLOCK If non-NIL, disables fcntl() locking on SVR4. This is done if fcntl() tends to hang for no good reason. Now that the fcntl() code checks for NFS files and no-ops the locking, this problem usually doesn't happen much any more. Defaults to NIL. GET_LOCKEACCESERROR / SET_LOCKEACCESERROR If non-NIL, give a warning if an attempt to create a .lock file gets an EACCES ("Permission denied") error. This usually means that somebody protected the system inbox directory (e.g. /var/mail) instead of making it public-write with the sticky bit. Defaults to non-NIL, since this is usually bad news. GET_LISTMAXLEVEL / SET_LISTMAXLEVEL The maximum depth of recusion that LIST will go on a * wildcard. Defaults to 20. GET_ANONYMOUSHOME / SET_ANONYMOUSHOME The anonymous use home directory name. typedef long (*readfn_t) (void *stream,unsigned long size,char *buffer); stream a designator suitable size a number of octets to read buffer a buffer of at least size octets for readin This function reads the given number of octets into the buffer, using the given stream. What sort of object the stream is depends upon the function and its caller, so you must make sure that the readfn is suitable for the caller's purpose. Common uses include support of the mailgets function (see below) and of reading from local files on systems with limited address space. typedef char *(*mailgets_t) (readfn_t f,void *stream,unsigned long size); f the readfn to use stream stream argument for the readfn size total number of octets to read This is the argument to the SET_GETS mail_parameter() call. This function must read size octets from the stream, using the readfn f. It may call f multiple times to accomplish this; this will read the data in a serial fashion. So, for example, if size is a megabyte and there is only 4K of available buffer space, it can call f 256 times to satisfy the request. There is no way to back up in the reading, so any processing or saving of the data must be done when it is read. The function mm_gets() in mail.c is a sample mailgets function; it reads the first MAXMESSAGESIZE of data into memory and discards the rest. typedef void *(*mailcache_t) (MAILSTREAM *stream,unsigned long msgno,long op); stream stream to cache manage msgno message to cache manage in the stream op cache management operation This function manages the c-client cache. Normally, a program will use the default c-client cache manager routine mm_cache(). However, a main program may want to supply its own cache manager, e.g. it may want to store the data on a disk file instead of in memory on DOS and Win16 where memory is tight. If you write your own cache manager, you need to examine the default mm_cache() manager closely, as well as paying close attention to what goes into an elt (a MESSAGECACHE element). It is highly likely that if you roll elts out to disk, you will want to set stream->scache and *NOT* use long elts (because long elts have ENVELOPE and BODY pointers that you would have to know how to write to disk and read back). The cache management functions are one of the following: CH_INIT Initialize the entire cache for the stream. This is called only when creating a new stream or when freeing it. The msgno argument is ignored. CH_SIZE Make sure that the cache is at least large enough to support msgno. This is a request to grow the cache if necessary, not shrink it. CH_MAKELELT Return a long elt for msgno, creating it if necessary. This is the underlying support function for mail_lelt(). CH_LELT Return the long elt for msgno, or NIL if it does not already exist. CH_MAKEELT Return an elt for msgno, creating it if necessary. This is the underlying support function for mail_elt(). CH_ELT Return the elt for msgno, or NIL if it does not already exist. CH_FREE Free the [l]elt for msgno. CH_EXPUNGE Free the [l]elt for msgno, and reclaim its position. All subsequent elts are renumbered with their elt->msgno decremented by 1. [Hence msgno+1 becomes msgno, etc.] This supports message expunging from the cache. typedef long (*tcptimeout_t) (long time); time total time spent since TCP operation started This function is called when a TCP operation times out. It is set by the SET_TIMEOUT mail_parameter(). The function can return non-zero to continue the TCP operation (e.g. after outputting a "do you still want to wait" prompt) or zero if it wants the TCP operation to abort and close. If the TCP operation aborts, it will likely cause the upper level IMAP, SMTP, etc. stream to abort and close as well. DRIVER *mail_valid (MAILSTREAM *stream,char *mailbox,char *purpose); stream if non-NIL, stream to use for validation mailbox mailbox name to validate purpose filled in as xxx in "Can't xxx" in error messages This function validates the given mailbox name. It successful, it returns the driver that can open that name if successful, otherwise it returns NIL. If stream is non-NIL, the mailbox name must be valid for the type of mailbox associated with that stream (e.g. an NNTP name can not be used with an IMAP stream). If purpose is non-NIL, an error message is passed via mm_log() when an error occurs. DRIVER *mail_valid_net (char *name,DRIVER *drv,char *host,char *mailbox); name mailbox name to validate drv driver name to validate against host buffer to return host name if non-NIL mailbox buffer to return remote mailbox name if non-NIL This function is an alternative to mail_valid_net_parse(). It validates the given mailbox name as a network name and makes sure that its service name is the same as the driver in drv. If successful, it returns drv, and copies the host and mailbox strings as needed. Otherwise it returns NIL. long mail_valid_net_parse (char *name,NETMBX *mb); name mailbox name to parse mb pointer to NETMBX structure to return This function parses a network mailbox name. If the name is a network mailbox name, it returns non-NIL, with the NETMBX structure loaded with the results form the parse. Mailbox Access Functions void mail_list (MAILSTREAM *stream,char *ref,char *pat); void mail_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); stream if non-NIL, stream to use ref mailbox reference string pat mailbox pattern string contents contents to search This function returns a list of mailboxes via the mm_list() callback. The reference is applied to the pattern in an implementation dependent fashion, and the resulting string is used to search for matching mailbox names. "*" is a wildcard which matches zero or more characters; "%" is a variant which does not descend a hierarchy level. Read the IMAP specification for more information. mail_scan() is a variant which takes a string to search for in the text of the mailbox. The string is a free-text string, without regard for message boundaries, and thus the choice of strings must be made with care. void mail_lsub (MAILSTREAM *stream,char *ref,char *pat); stream if non-NIL, stream to use ref mailbox reference string pat mailbox pattern string This function returns a list of subscribed mailboxes via the mm_lsub() callback. The reference is applied to the pattern in an implementation dependent fashion, and the resulting string is used to search for matching mailbox names in the subscription list. "*" is a wildcard which matches zero or more characters; "%" is a variant which does not descend a hierarchy level. Read the IMAP specification for more information. long mail_subscribe (MAILSTREAM *stream,char *mailbox); stream if non-NIL, stream to use mailbox mailbox name This function adds the given name to the subscription list. It returns T if successful, NIL if unsuccessful. If unsuccessful, an error message is returned via the mm_log() callback. long mail_unsubscribe (MAILSTREAM *stream,char *mailbox); stream if non-NIL, stream to use mailbox mailbox name This function removes the given name from the subscription list. It returns T if successful, NIL if unsuccessful. If unsuccessful, an error message is returned via the mm_log() callback. long mail_create (MAILSTREAM *stream,char *mailbox); stream if non-NIL, stream to use mailbox mailbox name This function creates a mailbox with the given name. It returns T if successful, NIL if unsuccessful. If unsuccessful, an error message is returned via the mm_log() callback. It is an error to create INBOX or a mailbox name which already exists. long mail_delete (MAILSTREAM *stream,char *mailbox); stream if non-NIL, stream to use mailbox mailbox name This function deletes the named mailbox. It returns T if successful, NIL if unsuccessful. If unsuccessful, an error message is returned via the mm_log() callback. It is an error to delete INBOX or a mailbox name which does not already exist. long mail_rename (MAILSTREAM *stream,char *old,char *newname); stream if non-NIL, stream to use old existing mailbox name newname new (not yet existing) mailbox name This function renames the old mailbox to the new mailbox name. It returns T if successful, NIL if unsuccessful. If unsuccessful, an error message is returned via the mm_log() callback. It is an error to reanme a mailbox that does not exist, or rename a mailbox to a name that already exists. It is permitted to rename INBOX; a new empty INBOX is created in its place. long mail_status (MAILSTREAM *stream,char *mbx,long flags); stream if non-NIL, stream to use mbx mailbox name flags option flags This function returns the status of the given mailbox name via the mm_status() callback. It returns T if successful, NIL if unsuccessful. If unsuccessful, an error message is returned via the mm_log() callback. The options are a bit mask with one or more of the following, indicating the data which should be returned. SA_MESSAGES number of messages in the mailbox SA_RECENT number of recent messages in the mailbox SA_UNSEEN number of unseen messages in the mailbox SA_UIDNEXT next UID value to be assigned SA_UIDVALIDITY UID validity value Note that, depending upon implementation, some of these values may be more costly to get than others. For example, calculating the number of unseen messages may require opening the mailbox and scanning all of the message flags. A mail_status() call should thus be used with option flags specifying only the data that is actually needed. MAILSTREAM *mail_open (MAILSTREAM *oldstream,char *name,long options); oldstream if non-NIL, stream to recycle name mailbox name to open options option flags. This function opens the mailbox and if successful returns a stream suitable for use by the other MAIL functions. If oldstream is non-NIL, an attempt is made to reuse oldstream as the stream for this mailbox; this is useful when you want to open another mailbox to the same IMAP or NNTP server without having to open a new connection. Doing this will close the previously open mailbox. The options are a bit mask with one or more of the following: OP_DEBUG Log IMAP protocol telemetry through mm_debug() OP_READONLY Open mailbox read-only. OP_ANONYMOUS Don't use or update a .newsrc file for news. OP_SHORTCACHE Don't cache envelopes or body structures OP_SILENT Don't pass mailbox events (internal use only) OP_PROTOTYPE Return the "prototype stream" for the driver associated with this mailbox instead of opening the stream OP_HALFOPEN For IMAP and NNTP names, open a connection to the server but don't open a mailbox. OP_EXPUNGE Silently expunge the oldstream before recycling NIL is returned if this function fails for any reason. MAILSTREAM *mail_close (MAILSTREAM *stream); MAILSTREAM *mail_close_full (MAILSTREAM *stream,long options); stream stream to close options option flags This function closes the MAIL stream and frees all resources associated with it that it may have created (subject to any handles existing). The options for mail_close_full() are a bit mask with one or more of the following: CL_EXPUNGE Silently expunge before closing This function always returns NIL, so it can be used as: stream = mail_close (stream); Handle Functions Handles are used when an entity that wishes to access the stream may survive the stream without knowing that it outlived it. For example, an object reading a message may have a handle to a stream, but the message selection object that spawned it (and which owns the stream) may have gone away. A stream can be closed or recycled while handles are pointing at it, but it is not completely freed until all handles are gone. A stream may have an arbitrary number of handles. MAILHANDLE *mail_makehandle (MAILSTREAM *stream); stream stream to make handle to This function creates and returns a handle to the stream. void mail_free_handle (MAILHANDLE **handle); handle pointer to handle to release This function frees the handle and notifies the stream that it has one fewer handle. If this is the last handle on the stream and the stream has been closed, then the stream is freed. MAILSTREAM *mail_stream (MAILHANDLE *handle); handle handle to look up This function returns the stream associated with the handle if and only if the stream still represents the same MAIL connection associated with the handle. Otherwise, NIL is returned (meaning that there is no active stream associated with this handle). Message Data Fetching Functions [Note!! There is an important difference between a "sequence" and a "msgno". A sequence is a string representing one or more messages in IMAP4-style sequence format ("n", "n:m", or combination of these delimited by commas), whereas a msgno is an int representing a single message.] void mail_fetchfast (MAILSTREAM *stream,char *sequence); void mail_fetchfast_full (MAILSTREAM *stream,char *sequence,long flags); stream stream to fetch on sequence IMAP-format set of message sequence numbers flags option flags This function causes a cache load of all the "fast" information (internal date, RFC 822 size, and flags) for the given sequence. Since all this information is also fetched by mail_fetchstructure(), this function is generally not used unless the OP_SHORTCACHE option in the mail_open() call is used. The options for mail_fetchfast_full() are a bit mask with one or more of the following: FT_UID The sequence argument contains UIDs instead of sequence numbers void mail_fetchflags (MAILSTREAM *stream,char *sequence); void mail_fetchflags_full (MAILSTREAM *stream,char *sequence,long flags); This function causes a fetch of the flags for the given sequence. This main reason for using this function is to update the flags in the local cache in case some other process changed the flags (multiple simultaneous write access is allowed to the flags) as part of a "check entire mailbox" (as opposed to "check for new messages") operation. The options for mail_fetchflags_full() are a bit mask with one or more of the following: FT_UID The sequence argument contains UIDs instead of sequence numbers ENVELOPE *mail_fetchenvelope (MAILSTREAM *stream,unsigned long msgno); ENVELOPE *mail_fetchstructure (MAILSTREAM *stream,unsigned long msgno, BODY **body); ENVELOPE *mail_fetchstructure_full (MAILSTREAM *stream,unsigned long msgno, BODY **body,long flags); stream stream to fetch on msgno message sequence number body pointer to where to return BODY structure if non-NIL flags option flags This function causes a fetch of all the structured information (envelope, internal date, RFC 822 size, flags, and body structure) for the given msgno and, in the case of IMAP, up to MAPLOOKAHEAD (a parameter in IMAP2.H) subsequent messages which are not yet in the cache. No fetch is done if the envelope for the given msgno is already in the cache. The ENVELOPE and the BODY for this msgno is returned. It is possible for the BODY to be NIL, in which case no information is available about the structure of the message body. The options for mail_fetchstructure_full() are a bit mask with one or more of the following: FT_UID The msgno argument is a UID This is the primary function for fetching non-text information about messages, and should be called before any attempt to reference cache information about this message via mail_elt(). char *mail_fetchheader (MAILSTREAM *stream,unsigned long msgno); char *mail_fetchheader_full (MAILSTREAM *stream,unsigned long msgno, STRINGLIST *lines,unsigned long *len,long flags); stream stream to fetch on msgno message sequence number lines list of header lines to fetch len returned length in octets flags option flags This function causes a fetch of the complete, unfiltered RFC 822 format header of the specified message as a text string and returns that text string. If the lines argument is non-NIL, it contains a list of header field names to use in subsetting the header text. Only those lines which have that header field name are returned, unless FT_NOT is set in which case only those lines which do not have that header field name are returned. If the len argument is non-NIL, it holds a pointer in which the length of the string in octets is returned. This is useful in cases where there may be an embedded null in the string. This function always returns a valid string pointer; if no header exists or if it can not be fetched (e.g. by a deceased IMAP stream) an empty string is returned. The options for mail_fetchheader_full() are a bit mask with one or more of the following: FT_UID The msgno argument is a UID FT_NOT The returned header lines are those that are not in the lines argument FT_INTERNAL The return string is in "internal" format, without any attempt to canonicalize to CRLF newlines FT_PREFETCHTEXT The RFC822.TEXT should be pre-fetched at the same time. This avoids an extra RTT on an IMAP connection if a full message text is desired (e.g. in a "save to local file" operation) char *mail_fetchtext (MAILSTREAM *stream,unsigned long msgno); char *mail_fetchtext_full (MAILSTREAM *stream,unsigned long msgno, unsigned long *len,long flags); stream stream to fetch on msgno message sequence number len returned length in octets flags option flags This function causes a fetch of the non-header text of the specified message as a text string and returns that text string. No attempt is made to segregate individual body parts. If the len argument is non-NIL, it holds a pointer in which the length of the string in octets is returned. This is useful in cases where there may be an embedded null in the string. This function always returns a valid string pointer; if no header exists or if it can not be fetched (e.g. by a deceased IMAP stream) an empty string is returned. The options for mail_fetchtext_full() are a bit mask with one or more of the following: FT_UID The msgno argument is a UID FT_PEEK Do not set the \Seen flag if it not already set FT_INTERNAL The return string is in "internal" format, without any attempt to canonicalize to CRLF newlines char *mail_fetchbody (MAILSTREAM *stream,unsigned long msgno,char *sec, unsigned long *len); char *mail_fetchbody_full (MAILSTREAM *stream,unsigned long msgno,char *sec, unsigned long *len,long flags); stream stream to fetch on msgno message sequence number sec section specifier len returned length in octets flags option flags This function causes a fetch of the particular section of the body of the specified message as a text string and returns that text string. The section specification is a string of integers delimited by period which index into a body part list as per the IMAP4 specification. Body parts are not decoded by this function; see rfc822_base64() and rfc822_quotedprintable(). If the len argument is non-NIL, it holds a pointer in which the length of the string in octets is returned. This is useful in cases where there may be an embedded null in the string. This function may return NIL on error. The options for mail_fetchbody_full() are a bit mask with one or more of the following: FT_UID The msgno argument is a UID FT_PEEK Do not set the \Seen flag if it not already set FT_INTERNAL The return string is in "internal" format, without any attempt to canonicalize to CRLF newlines unsigned long mail_uid (MAILSTREAM *stream,unsigned long msgno); stream stream to fetch on msgno message sequence number This function returns the UID for the given message sequence number. void mail_fetchfrom (char *s,MAILSTREAM *stream,unsigned long msgno, long length); s destination string stream stream to fetch on msgno message sequence number length maximum field length This function writes a "from" string of the specified length for the specified message, suitable for display to the user in a menu line, into the string pointed to by s. If the personal name of the first address in the envelope's from item is non-NIL, it is used; otherwise a string is created by appending the mailbox of the first address, an "@", and the host of the first address. The string is trimmed or padded with trailing spaces as necessary to make its length match the length argument. void mail_fetchsubject (char *s,MAILSTREAM *stream,unsigned long msgno, long length); s destination string stream stream to fetch on msgno message sequence number length maximum field length This function returns a "subject" string of the specified length for the specified message, suitable for display to the user in a menu line. The envelope's subject item is copied and trimmed as necessary to make its length be no more what the caller requested. Unlike mail_fetchfrom(), this function can return a string of shorter length than what the caller requested. LONGCACHE *mail_lelt (MAILSTREAM *stream,unsigned long msgno); MESSAGECACHE *mail_elt (MAILSTREAM *stream,unsigned long msgno); stream stream to access msgno message sequence number This function returns the cache entry for the specified message. Although it will create a cache entry if it does not already exist, that functionality is for internal use only. This function should never be called without having first called mail_fetchfast() or mail_fetchstructure() on the message first. A cache entry holds the internal date/time, flags, and RFC 822 size of a message. It holds other data as well, but that is for internal use only. mail_lelt() is a variant that returns a `long' cache entry, which consists of an cache entry (as a structure, not a pointer), an envelope pointer, and a body pointer. This is used in conjunction with the elt lock count functionality, to allow an application to associate the cached envelope and body of a message with an open window even if the message is subsequently expunged or if the stream is closed. Unless your application wants to look at cached envelopes and bodies even after the message is expunged or the stream is closed, it should not use mail_lelt(). Instead, it should use a returned elt from mail_elt() and use the elt->msgsno as the argument to mail_fetchstructure(). BEWARE: the behavior of mail_lelt() is undefined if the stream is open with OP_SHORTCACHE. mail_lelt() is extremely special purpose, and should only be used in sophisticated special purpose applications after discussing its use with the c-client author. If you think you need this function, you are probably mistaken. In almost all cases, you should use mail_elt() and mail_fetchstructure() instead. Message Status Manipulation Functions void mail_setflag (MAILSTREAM *stream,char *sequence,char *flag); void mail_setflag_full (MAILSTREAM *stream,char *sequence,char *flag, long flags); stream stream to use sequence IMAP-format set of message sequence numbers flag IMAP-format flag string flags option flags This function causes a store to add the specified flag to the flags set for the messages in the specified sequence. If there is any problem in setting flags, a message will be passed to the application via the mm_log() facility. The options for mail_setflag_full() are a bit mask with one or more of the following: ST_UID The sequence argument contains UIDs instead of sequence numbers ST_SILENT Do not update the local cache with the new value of the flags. This is useful to save network bandwidth, at the cost of invalidating the cache. void mail_clearflag (MAILSTREAM *stream,char *sequence,char *flag); void mail_clearflag_full (MAILSTREAM *stream,char *sequence,char *flag, long flags); stream stream to use sequence IMAP-format set of message sequence numbers flag IMAP-format flag string flags option flags This function causes a store to delete the specified flag from the flags set for the messages in the specified sequence. If there is any problem in clearing flags, a message will be passed to the application via the mm_log() facility. The options for mail_setflag_full() are a bit mask with one or more of the following: ST_UID The sequence argument contains UIDs instead of sequence numbers ST_SILENT Do not update the local cache with the new value of the flags. This is useful to save network bandwidth, at the cost of invalidating the cache. Mailbox Searching void mail_search (MAILSTREAM *stream,char *criteria); void mail_search_full (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm, long flags); stream stream to search charset MIME character set to use when searching strings pgm search program flags option flags This function causes a mailbox search, using the given MIME charset (NIL means the default, US-ASCII) and the given search program. A search program is a structure that holds the following data: SEARCHSET *msgno; a set of message sequence numbers SEARCHSET *uid; a set of unique identifiers SEARCHOR *or; OR result of two search programs SEARCHPGMLIST *not; AND result of list of NOT'ed search programs SEARCHHEADER *header; message headers STRINGLIST *bcc; string(s) appear in bcc list STRINGLIST *body; string(s) appear in message body text STRINGLIST *cc; string(s) appear in cc list STRINGLIST *from; string(s) appear in from STRINGLIST *keyword; user flag string(s) set STRINGLIST *unkeyword; user flag strings() not set STRINGLIST *subject; string(s) appear in subject STRINGLIST *text; string(s) appear in message header or body STRINGLIST *to; string(s) appear in to list unsigned long larger; larger than this many octets unsigned long smaller; smaller than this many octes The following dates are in form: ((year - BASEYEAR) << 9) + (month << 5) + day unsigned short sentbefore; sent before this date unsigned short senton; sent on this date unsigned short sentsince; sent since this date unsigned short before; received before this date unsigned short on; received on this date unsigned short since; received since this date unsigned int answered : 1; message answered unsigned int unanswered : 1; message not answered unsigned int deleted : 1; message deleted unsigned int undeleted : 1; message not deleted unsigned int draft : 1; message is a draft unsigned int undraft : 1; message is not a draft unsigned int flagged : 1; message flagged as urgent unsigned int unflagged : 1; message not flagged as urgent unsigned int recent : 1; message recent since last parse of mailbox unsigned int old : 1; message not recent since last parse of mailbox unsigned int seen : 1; message read unsigned int unseen : 1; message not read The following auxillary structures are used by search programs: SEARCHHEADER: header line searching char *line; header line field name char *text; text header line SEARCHHEADER *next; next SEARCHHEADER in list (AND'ed) SEARCHSET: message number set unsigned long first; first number in set unsigned long last; if non-zero, last number in set SEARCHSET *next; next SEARCHSET in list (AND'ed) SEARCHOR: two search programs, OR'ed together SEARCHPGM *first; first program SEARCHPGM *second; second program SEARCHOR *next; next SEARCHOR in list SEARCHPGMLIST: list of search programs SEARCHPGM *pgm; search program (AND'd with others in list) SEARCHPGMLIST *next; next SEARCHPGM in list mail_search(), the older interface, accepts a search criteria argument as a character string in IMAP2 (RFC-1176) format. Do not try to use any IMAP4 search criteria with this interface. The application's mm_searched() function is called for each message that matches the search criteria. In addition, after the search is completed, the "fast" information (see mail_fetchfast_full() and envelopes of the searched messages are fetched (this is called pre-fetching). If there is any problem in searching, a message will be passed to the application via the mm_log() facility. The flags for mail_search_full() are a bit mask with one or more of the following: SE_UID Return UIDs instead of sequence numbers SE_FREE Return the search program to free storage after finishing SE_NOPREFETCH Don't prefetch searched messages. unsigned long *mail_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags); stream stream to sort charset MIME character set to use when sorting strings spg search program pgm sort program flags option flags This function is a variant of mail_search_full(). It accepts an additional argument, a sort program, which specifies one or more sort rules to be applied to the result. If the searching and sorting are successful, it returns a 0-terminated vector of message sequence numbers (or UIDs if SE_UID is set). This vector is created out of free storage, and must be freed with fs_give() when finished with it. A sort program is a structure that holds the following data: unsigned int reverse : 1; reverse sorting of this key short function; sort rule, one of the following: SORTDATE message Date SORTARRIVAL arrival date SORTFROM mailbox in first From address SORTSUBJECT message Subject SORTTO mailbox in first To address SORTCC mailbox in first cc address SORTSIZE size of message in octets SORTPGM *next; next sort program to be applied if two or more messages collate identically with this rule The flags for mail_search_full() are a bit mask with one or more of the following: SE_UID Return UIDs instead of sequence numbers SE_FREE Return the search program to free storage after finishing SE_NOPREFETCH Don't prefetch searched messages. SO_FREE Return the sort program to free storage after finishing Miscellaneous Mailbox and Message Functions long mail_ping (MAILSTREAM *stream); stream string to ping The function pings the stream to see if it is still active. It may discover new mail; this is the preferred method for a periodic "new mail check" as well as a "keep alive" for servers which have an inactivity timeout. It returns T if the stream is still alive, NIL otherwise. If new mail is found, the application's mm_exists() function is called with the newly-determined number of messages in the mailbox. void mail_check (MAILSTREAM *stream); stream stream to checkpoint This function causes a mailstore-defined checkpoint of the mailbox. This may include such things as a writeback to disk, a check for flag changes in a shared mailbox, etc. It is not a "check for new mail"; mail_ping() performs this function (as potentially does any other function). The status of the check is passed to the application via the mm_log() facility. void mail_expunge (MAILSTREAM *stream); stream string to expunge This function causes an expunge (permanent removal of messages which are marked as deleted) of the mailbox. The application's mm_expunged() function is called for each message that has been expunged. The application's mm_exists() function is called at the start and end of the expunge to ensure synchronization. The status of the expunge is passed to the application via the mm_log() facility. Note that the decrementing of msgno's for subsequent messages happens immediately; for example, if three consequtive messages starting at msgno 5 are expunged, mm_expunged() will be called with a msgno of 5 three times. long mail_copy (MAILSTREAM *stream,char *sequence,char *mailbox); long mail_move (MAILSTREAM *stream,char *sequence,char *mailbox); long mail_copy_full (MAILSTREAM *stream,char *sequence,char *mailbox, long options); stream stream to copy sequence IMAP-format set of message numbers mailbox destination mailbox name options option flags This function causes the messages in the specified sequence to be copied to the specified mailbox. T is returned if the copy is successful. mail_move() is equivalent to setting CP_MOVE in the options. If there is any problem in copying, a message will be passed to the application via the mm_log() facility and the function returns NIL. No copying is actually done in this case. Note that the mailbox must be on the same host as the stream and is a mailbox of the type of the source mailbox only. The flags for mail_search_full() are a bit mask with one or more of the following: CP_UID The sequence argument contains UIDs instead of sequence numbers CP_MOVE Delete the messages from the current mailbox after copying to the destination. long mail_append (MAILSTREAM *stream,char *mailbox,STRING *message); long mail_append_full (MAILSTREAM *stream,char *mailbox,char *flags,char *date, STRING *message); stream stream to use if non-NIL (in the IMAP case) mailbox destination mailbox name flags flags to set on message if non-NIL date internal date (received date) to set on message if non-NIL message string structure of message to write This function writes the message in the string structure to the destination mailbox, along with the flags and date if specified. This is useful in those cases where you can't use mail_copy(), e.g. when copying from one server to another; you can always fetch the message and then mail_append() it to the destination. It may also be useful for maintaining an outbox of your outgoing mail. void mail_gc (MAILSTREAM *stream,long gcflags); stream stream to GC if non-NIL (else GC's all streams) flags option flags This function garbage collects (purges) the cache of entries of a specific type. Some drivers do not allow purging of particular cache types, and an attempt to do so is ignored. The flags for mail_gc() are a bit mask with one or more of the following: GC_ELT message cache elements GC_ENV ENVELOPEs and BODYs GC_TEXTS cached texts Date/Time Handling Functions char *mail_date (char *string,MESSAGECACHE *elt); string destination string elt message cache element containing date This function accepts a message cache element that contains date information, and writes an IMAP-4 date string, that is, one in form: dd-mmm-yyyy hh:mm:ss +zzzz based upon the data in the elt. The destination string must be large enough to hold this string. char *mail_cdate (char *string,MESSAGECACHE *elt); string destination string elt message cache element containing date This function accepts a message cache element that contains date information, and writes a ctime() format date string, that is, one in form: www mmm dd hh:mm:ss yyyy\n based upon the data in the elt. The destination string must be large enough to hold this string. long mail_parse_date (MESSAGECACHE *elt,char *string); elt message cache element to store parsed date string source date string This function parses the date/time stored in the given string, in format: [www,] date [[hh:mm[:ss][-zzz| +zzzz] where the date can be any of: mm/dd/yy, mm/dd/yyyy, dd-mmm-yy, dd-mmm-yyyy, dd mmm yy, dd mmm yyyy and stores the result of the parse in the elt. If the parse is successful, T is returned, else NIL. unsigned long mail_longdate (MESSAGECACHE *elt); elt message cache element containing date. This function accepts a message cache element that contains date information, and returns the number of days since the base time of the imap-4 toolkit. At present, this is the same as the Unix time() value for that date/time, and hence can be used for functions such as utime(). Utility Functions void mail_debug (MAILSTREAM *stream); stream stream to debug This function enables telemetry logging for this stream. All telemetry is passed to the application via the mm_dlog() facility. void mail_nodebug (MAILSTREAM *stream); stream stream to disable debugging This function disables telemetry logging for this stream. long mail_sequence (MAILSTREAM *stream,char *sequence); stream stream to set the sequence bits sequence IMAP-format message set string This function parses the given sequence string for message numbers, sets the sequence bit in the stream's message cache element of all messages in the sequence (and turns it off in all other message cache elements). If the parse is successful, T is returned, else NIL. long mail_uid_sequence (MAILSTREAM *stream,char *sequence); stream stream to set the sequence bits sequence IMAP-format message set string This function parses the given sequence string for unique identifiers, sets the sequence bit in the stream's message cache element of all messages in the sequence (and turns it off in all other message cache elements). If the parse is successful, T is returned, else NIL. long mail_parse_flags (MAILSTREAM *stream,char *flag,unsigned long *uf); stream stream (used to get user flags) flag IMAP-format flag string to parse uf returned location of user flags The function parses the given flag string, and returns the system flags as its return value and the user flags in the location pointed to by the uf argument. If there is an error in parse, a log message is issued via mm_log() and this function returns NIL. unsigned long mail_filter (char *text,unsigned long len,STRINGLIST *lines, long flags); text RFC 822 text to filter len length in octets in the text argument lines string list of header file names to filter flags option flags This function supports the header lines filtering function of mail_fetchheader_full(). The lines argument contains a list of header field names to use in subsetting the header text. Only those lines which have that header field name are returned, unless FT_NOT is set in which case only those lines which do not have that header field name are returned. The options for mail_filter() are a bit mask with one or more of the following: FT_NOT The returned header lines are those that are not in the lines argument long mail_search_msg (MAILSTREAM *stream,unsigned long msgno,char *charset, SEARCHPGM *pgm); stream stream to search msgno message number of message to inspect charset character set of search strings pgm search program to test This function implements mail_search_full() locally in cases when it is not done by a server (e.g. local mail files, NNTP/POP). It inspects the given message on that stream to see if it matches the criteria or not. If it matches, T is returned, else NIL. SEARCHPGM *mail_criteria (char *criteria); criteria IMAP2-format search criteria string This function accepts an IMAP2-format search criteria string and parses it. If the parse is successful, it returns a search program suitable for use in mail_search_full(). WARNING: This function does not accept IMAP4 search criteria. The source string must be writeable (this restriction was also in the old IMAP2 c-client). Data Structure Instantiation/Destruction functions These functions are used to obtain structures from free storage and to release them. ENVELOPE *mail_newenvelope (void); ADDRESS *mail_newaddr (void); BODY *mail_newbody (void); BODY *mail_initbody (BODY *body); PARAMETER *mail_newbody_parameter (void); PART *mail_newbody_part (void); STRINGLIST *mail_newstringlist (void); SEARCHPGM *mail_newsearchpgm (void); SEARCHHEADER *mail_newsearchheader (char *line); SEARCHSET *mail_newsearchset (void); SEARCHOR *mail_newsearchor (void); SEARCHPGMLIST *mail_newsearchpgmlist (void); SORTPGM *mail_newsortpgm (void); These functions, all named mail_new...(), create a new structure of the given type and initialize all of its elements to zero or empty. void mail_free_body (BODY **body); void mail_free_body_parameter (PARAMETER **parameter); void mail_free_body_part (PART **part); void mail_free_cache (MAILSTREAM *stream); void mail_free_elt (MESSAGECACHE **elt); void mail_free_lelt (LONGCACHE **lelt); void mail_free_envelope (ENVELOPE **env); void mail_free_address (ADDRESS **address); void mail_free_stringlist (STRINGLIST **string); void mail_free_searchpgm (SEARCHPGM **pgm); void mail_free_searchheader (SEARCHHEADER **hdr); void mail_free_searchset (SEARCHSET **set); void mail_free_searchor (SEARCHOR **orl); void mail_free_searchpgmlist (SEARCHPGMLIST **pgl); void mail_free_sortpgm (SORTPGM **pgm); These functions, all named mail_free_...(), take a pointer to a structure pointer, free all contained strings and structures within the structure, and finally free the structure itself and set its pointer to NIL. For example, mail_free_envelope() frees all the ADDRESS structures contained in the envelope. Normally, mail_free_elt() and mail_free_lelt() are used only if the main program has a private pointer to cache elements. If so, it is expected to increment the cache element's lockcount when it makes a private pointer, and to call this function when it is finished with it. Authentication Functions char *mail_auth (char *mechanism,authresponse_t resp,int argc,char *argv[]); mechanism authentication mechanism name resp callback function for providing responses argc main() function argc value argv main() function argv value This server function searches the list of authenticators that was established by auth_link() for an authenticator with the given name. If an authenticator is found, authentication is initialized. The function pointed to by resp is called as the authenticator requires responses. AUTHENTICATOR *mail_lookup_auth (unsigned int i); i position in authenticator list This function returns the nth authenticator in the list, where n is the value of it. unsigned int mail_lookup_auth_name (char *mechanism); mechanism authentication mechanism name This function searches the list of authenticators for an authenticator with the given name, and returns its position in the authenticator list. The functions below are provided by c-client client drivers or by servers to support the protocol-dependent parts of authentication. typedef void *(*authchallenge_t) (void *stream,unsigned long *len); stream stream to read challenge len pointer to returned length in octets This driver function is called by an authenticator to read a challenge from the given protocol stream in a protocol-dependent way. It returns that challenge in binary and its length in octets to the authenticator. typedef long (*authrespond_t) (void *stream,char *s,unsigned long size); stream stream to send response s response string size length of response string in octets This driver function is called by an authenticator to send a challenge response to the given stream in a protocol-dependent way. It returns T if successful, NIL if failure. typedef char *(*authresponse_t) (void *challenge,unsigned long clen, unsigned long *rlen); challenge challenge string clen length of challenge string in octets rlen pointer to returned length of response string This server function is called with a challenge string of clen octets. It sends, according to whatever protocol (IMAP, POP, etc.) it uses, and returns the received response and response length in octets. typedef long (*authclient_t) (authchallenge_t challenger, authrespond_t responder,NETMBX *mb,void *s, unsigned long trial); challenger pointer to protocol-dependent challenge reader function responder pointer to protocol-dependent response sender function mb NETMBX struct of the mailbox desired to open s stream for protocol-dependent routines to use trial number of authentication attempts remaining This client authenticator function negotiates reading challenges and sending responses for a particular authenticator (Kerberos, etc.) over the protocol, and returns T if authenticated or NIL if failed. typedef char *(*authserver_t) (authresponse_t responder,int argc,char *argv[]); responder pointer to protocol-dependent responder function argc main() function argc value argv main() function argv value This server authenticator function negotiates sending challenges and reading responses for a particular authenticator (Kerberos, etc.), and returns either the authenticated user name or NIL if authentication failed. Network Access Functions These functions provide a layer of indirection between the TCP routines and upper level routines. This makes it possible to insert additional code (e.g. privacy or checksum handling). NETSTREAM *net_open (char *host,char *service,unsigned long port); host host name service contact service name port contact port number This function opens a TCP connection to the given host and service or port. NETSTREAM *net_aopen (NETMBX *mb,char *service,char *usrbuf); NETMBX parsed mailbox specification service stream to open (at present, only /etc/rimapd is used) usrbuf buffer to return login user name This function attempts to open a preauthenticated connection to the given mailbox and service. It will return the login user name of the preauthenticated connection, as well as an open network stream, if successful. char *net_getline (NETSTREAM *stream); stream network stream to read This routine reads a text line from the stream. It calls stream->dtb->getline, which normally points to tcp_getline() but can be set to some other function. long net_getbuffer (void *stream,unsigned long size,char *buffer); stream network stream to read size length of data in octets buffer buffer of at least size octets This routine reads data from the stream. It calls stream->dtb->getbuffer, which normally points to tcp_getbuffer() but can be set to some other function. long net_soutr (NETSTREAM *stream,char *string); stream network stream to write string null-terminated string to output This routine writes a null-terminated string to the stream. It calls stream->dtb->soutr, which normally points to tcp_soutr() but can be set to some other function. long net_sout (NETSTREAM *stream,char *string,unsigned long size); stream network stream to write string string to output size length of string in octets This routine writes a string of length size to the stream. It calls stream->dtb->sout, which normally points to tcp_sout() but can be set to some other function. void net_close (NETSTREAM *stream); stream stream to close This routine closes the stream. It calls stream->dtb->close, which normally points to tcp_close() but can point to some other function. char *net_host (NETSTREAM *stream); stream stream to inspect This routine returns the remote host name of the stream. It calls stream->dtb->host, which normally points to tcp_host() but can point to some other function. unsigned long net_port (NETSTREAM *stream); stream stream to inspect This routine returns the remote port number of the stream. It calls stream->dtb->port, which normally points to tcp_port() but can point to some other function. char *net_localhost (NETSTREAM *stream); stream stream to inspect This routine returns the local host name of the stream. It calls stream->dtb->localhost, which normally points to tcp_localhost() but can point to some other function. Subscription Management Functions long sm_subscribe (char *mailbox); mailbox mailbox name to subscribe This function adds the given mailbox name to the local subscription list, and returns T if successful, NIL if failure. long sm_unsubscribe (char *mailbox); mailbox mailbox name to unsubscribe This function removes the given mailbox name from the local subscription list, and returns T if successful, NIL if failure. char *sm_read (void **sdb); sdb data to use in subsequent calls, or NIL if first call This function returns the local subscription list as null terminated strings. Each call returns the next element in the list. The first call should be with sdb pointing to a NIL pointer; this will be filled in for subsequent calls. At the last call, NIL will be returned. Miscellaneous Utility Functions char *ucase (char *string); string string to convert This function converts each lowercase character of the specified string to uppercase and returns the string. char *lcase (char *string); string string to convert This function converts each uppercase character of the specified string to lowercase and returns the string. char *cpystr (char *string); string string to copy This function makes a copy of the string from free storage and returns the copy. long find_rightmost_bit (long *valptr); valptr pointer to value to search This function returns -1 if the 32-bit value pointed to by valptr is non-zero, otherwise it returns the bit number (0 = LSB, 31 = MSB) of the right-most bit in that value. This is used to convert from the bits in the cache's userflags item to an index into the stream's userFlags array of flag texts. long min (long i,long j); i first argument j second argument This function returns the minimum of the two integers. long max (long i,long j); i first argument j second argument This function returns the maximum of the two integers. long search (char *s,long c,char *pat,long patc); s string to search c size of string pat pattern to search in string patc size of pattern This function does a fast case-independent search for the given pattern in pat (length patc) in base string s, and returns T if the pattern is found in the string. long pmatch (char *s,char *pat,delim); long pmatch_full (char *s,char *pat,delim); s string to match pat wildcard (* and %) to match in pattern delim hierarchy delimiter This function returns T if the given wildcard pattern matches the string in s with hierarchy delimiter delim. Otherwise NIL is returned. long dmatch (char *s,char *pat,char delim); s string to match pat wildcard (* and %) to match in pattern delim hierarchy delimiter This function returns T if the given wildcard pattern matches the directory. If not, then none of the elements in the directory are considered for recursive checking with pmatch_full(). SMTP Functions SMTPSTREAM *smtp_open (char **hostlist,long debug); hostlist vector of SMTP server host names to try debug non-zero if want protocol telemetry debugging This function opens an SMTP connection to a one of the hosts in the host list and if successful returns a stream suitable for use by the other SMTP functions. The hosts are tried in order until a connection is successfully opened. If debug is non-NIL, protocol telemetry is logged via mm_dlog(). NIL is returned if this function fails to open a connection to any of the hosts in the list. void smtp_close (SMTPSTREAM *stream); stream stream to close This function closes the SMTP stream and frees all resources associated with it that it may have created. long smtp_mail (SMTPSTREAM *stream,char *type,ENVELOPE *msg,BODY *body); stream stream to transmit mail type mail type (MAIL, SEND, SAML, SOML) msg message envelope body message body This function negotiates an SMTP transaction of the specified type (one of "MAIL", "SEND", "SAML", or "SOML") to deliver the specified message. This function returns T if success or NIL if there is any failure. The text reason for the failure is in stream->reply item; if it is associated with a recipient it is also in that address' address->error item. void smtp_debug (SMTPSTREAM *stream); stream stream to enable debugging telemetry This function enables SMTP protocol telemetry logging for this stream. All SMTP protocol operations are passed to the application via the mm_dlog() facility. void smtp_nodebug (SMTPSTREAM *stream); stream stream to disable debugging telemetry This function disables SMTP protocol telemetry logging for this stream. typedef void (*smtpverbose_t) (char *buffer); buffer pointer to verbose reply buffer This is the argument to the SET_SMTPVERBOSE mail_parmameter() call. If this function pointer is non-NIL, then if a verbose SMTP response (with SMTP code less than 100) is received, this function is called with that response text as its argument. NNTP Functions NNTPSTREAM *nntp_open (char **hostlist,long debug); hostlist vector of NNTP server host names to try debug non-zero if want protocol telemetry debugging This function opens an NNTP connection to a one of the hosts in the host list and if successful returns a stream suitable for use by the other MTP functions. The hosts are tried in order until a connection is successfully opened. If debug is non-NIL, protocol telemetry is logged via mm_dlog(). NIL is returned if this function fails to open a connection to any of the hosts in the list. void nntp_close (NNTPSTREAM *stream); stream stream to close This function closes the NNTP stream and frees all resources associated with it that it may have created. long nntp_mail (NNTPSTREAM *stream,ENVELOPE *msg,BODY *body); stream stream to transmit mail msg message envelope body message body This function negotiates an NNTP posting transaction to deliver the specified news message. This function returns T if success or NIL if there is any failure. The text reason for the failure is in stream->reply item; if it is associated with a recipient it is also in that address' address->error item. RFC 822 Support Functions Although rfc822.c contains several additional functions besides these, only the functions documented here should be used by applications. The other functions are for internal use only. void rfc822_header (char *header,ENVELOPE *env,BODY *body); header buffer to write RFC 822 header env message ENVELOPE (used to obtain RFC 822 information) body message BODY (used to obtain MIME information) This function writes an RFC 822 format header into header based on the information in the envelope and body. The header buffer must be large enough to contain the full text of the resulting header. void rfc822_write_address (char *dest,ADDRESS *adr); dest buffer to write address list adr RFC 822 ADDRESS list This function writes an RFC 822 format address list into dest based on the information in adr. The dest buffer must be large enough to contain the full text of the resulting address list. void rfc822_parse_msg (ENVELOPE **en,BODY **bdy,char *s,unsigned long i, STRING *b,char *host,char *tmp); en destination pointer where message ENVELOPE will be stored bdy destination pointer where message BODY will be stored s RFC 822 header to parse (character string) i length of RFC 822 header b stringstruct of message body host default host name if an address lacks an @host. temp scratch buffer, must be long enough to hold unwound header lines (a buffer that is i octets long is OK) This function parses the RFC 822 header pointed to by s with body pointed to by string structure b into the specified destination envelope and body pointers, using host as the default host name and tmp as a scratch buffer. New ENVELOPE and BODY structures are created; when finished with them the application must free them with mail_free_envelope() and mail_free_body(). Any parsing errors are noted via the mm_log() mechanism using log type PARSE. void rfc822_parse_adrlist (ADDRESS **lst,char *string,char *host); lst destination pointer where ADDRESS will be stored string string of addresses to parse host default host name if an address lacks an @host. This function parses the address list in the given string into an address list in lst. Any addresses missing a host name are have the host name defaulted from the host argument. If the destination list is non-empty it appends the new addresses to the list. Any parsing errors are noted via the mm_log() mechanism using log type PARSE. long rfc822_output (char *t,ENVELOPE *env,BODY *body,soutr_t f,void *s, long ok8bit); t scratch buffer, large enough to hold message header env message ENVELOPE body message BODY f I/O function to write to s stream for I/O function f ok8bit non-zero if OK to output 8-bit data This function writes the message described with the given envelope and body. Any body part contents of type ENCBINARY is converted to ENCBASE64 before sending. If ok8bit is NIL, any message data of type ENC8BIT is converted to ENCQUOTEDPRINTABLE before sending; if ok8bit is non-NIL then ENC8BIT data is sent as-is. T is returned if the function succeeds, else NIL is returned. The function f is typically net_soutr(), but it can be any function which matches typedef long (*soutr_t) (void *stream,char *string); where stream holds sufficient information to enable the output routine to know where to output to, and the string is a null-terminated string to output. This function returns either T or NIL, and that value is passed up to rfc822_output() for its return. void *rfc822_base64 (char *src,unsigned long srcl,unsigned long *len); src source string srcl size of source string in octets len pointer to where destination string length in octets will be returned This function decodes a BASE64 body part given a source string and its length. The decoded body part as a sequence of binary octets is returned, and its length is returned in len. char *rfc822_qprint (char *src,unsigned long srcl,unsigned long *len); src source string srcl size of source string in octets len pointer to where destination string length in octets will be returned This function decodes a QUOTED-PRINTABLE body part given a source string and its length. The decoded body part as an 8-bit character string is returned, and its length is returned in len. Operating System-Dependent Public Interface These functions are in OS-dependent code, and are rewritten each time c-client is ported to a new operating system. void rfc822_date (char *date); date buffer to write the date, must be large enough This function is called to get the current date and time in an RFC 822 format string into the given buffer. void *fs_get (size_t size); size number of octets requested This function allocates and returns a block of free storage of the specified size. Unlike malloc(), there is no failure return; this function must return with the requested storage. void fs_resize (void **block,size_t size); block pointer to pointer to block to be resized size new size in octets This function resizes the free storage block, updating the pointer if necessary. Unlike realloc(), there is no failure return; this function must return with the requested storage. void fs_give (void **block); block pointer to pointer to block to free This function releases a block of free storage allocated by fs_get(). It also erases the block pointer, so it isn't necessary to do this in the application. void fatal (char *string); string message string This function is called when an "impossible" error is detected and the client wishes to crash. The string should contain a reason. char *strcrlfcpy (char **dst,long *dstl,char *src,long srcl); dst pointer to destination string pointer dstl pointer to destination string size src source strin srcl source string size This function is called to copy into a destination string dst of size dstl (resized if necessary), a CRLF newline form string from local format string src of size srcl. TCPSTREAM *tcp_open (char *host,long port); TCPSTREAM *tcp_aopen (char *host,char *service); char *tcp_getline (TCPSTREAM *stream); long tcp_getbuffer (TCPSTREAM *stream,long size,char *buffer); long tcp_soutr (TCPSTREAM *stream,char *string); void tcp_close (TCPSTREAM *stream); char *tcp_host (TCPSTREAM *stream); unsigned long tcp_port (TCPSTREAM *stream); char *tcp_localhost (TCPSTREAM *stream); These functions are TCP-specific versions of the more general net_xxx() functions. These should not be called directly by applications. char *tcp_clienthost (char *dst); dst destination string buffer This function should be called only by a server called by inetd or similar mechanism which maps standard input to a network socket. It returns the host name of the other end (e.g. the client of a server) using the given string buffer, or NIL if it can't get this information. Main Program Callbacks All applications which use the c-client must have the following callbacks to handle events from c-client. Note that in any callback which involves a mail stream, the stream is locked and you can not recursively call c-client from the callback. This may also be true in callbacks which do not have a stream; in general, the rule is "do not call c-client, especially any mail_xxx() function, from a c-client callback". void mm_flags (MAILSTREAM *stream,unsigned long number); stream stream where event happened number message number This function is called when c-client manipulates the flags for the given message number. This alerts the application that it may need to inspect that message's flags to see if there are any interesting changes. void mm_status (MAILSTREAM *stream,char *mailbox,MAILSTATUS *status); stream stream where event happened mailbox mailbox name for this status status MAILSTATUS structure with message status This function is called when c-client reports status of a mailbox (generally as the result of a mail_status() function call). The returned MAILSTATUS structure has the following members: long flags; validity flags. These are the same as the SA_xxx option flags in the mail_status() call, and they indicate which of the other members of the MAILSTATUS structure have usable data (i.e. if SA_MESSAGES is not set, do not believe status->messages!!). unsigned long messages; number of messages if SA_MESSAGES unsigned long recent; number of recent messages if SA_RECENT unsigned long unseen; number of unseen messages if SA_UNSEEN unsigned long uidnext; next UID to be assigned if SA_UIDNEXT unsigned long uidvalidity; UID validity value if SA_UIDVALIDITY void mm_searched (MAILSTREAM *stream,unsigned long number); stream stream where event happened number message number This function is called to notify the main program that this message number matches a search (generally as the result of a mail_search_full() function call). void mm_exists (MAILSTREAM *stream,unsigned long number); stream stream where event happened number message number This function is called to notify the main program that there are this many messages in the mailbox. It is also used to notify the main program of new mail, by announcing a higher number than the main program was previously aware. void mm_expunged (MAILSTREAM *stream,unsigned long number); stream stream where event happened number message number This function is called to notify the main program that this message number has been expunged from the mail file and that all subsequent messages are now referenced by a message number one less than before. This implicitly decrements the number of messages in the mailbox. void mm_list (MAILSTREAM *stream,char delim,char *name,long attrib); stream stream where event happened delim hierarchy delimiter name mailbox name attrib mailbox attributes This function is called to notify the main program that this mailbox name matches a mailbox listing request (generally as the result of a mail_list() function call). The hierarchy delimiter is a character that separates out levels of hierarchy in mailbox names. The attributes are a bit mask with one of the following: LATT_NOINFERIORS it is not possible for there to be any hierarchy inferiors to this name (that is, this name followed by the hierarchy delimiter and additional name characters). LATT_NOSELECT this is not a mailbox name, just a hierarchy level, and it may not be opened by mail_open() LATT_MARKED this mailbox may have recent messages LATT_UNMARKED this mailbox does not have any recent messages void mm_lsub (MAILSTREAM *stream,char delim,char *name,long attrib); stream stream where event happened delim hierarchy delimiter name mailbox name attrib mailbox attributes This function is called to notify the main program that this mailbox name matches a subscribed mailbox listing request (generally as the result of a mail_lsub() function call). The hierarchy delimiter is a character that separates out levels of hierarchy in mailbox names. The attributes are a bit mask with one of the following: LATT_NOINFERIORS it is not possible for there to be any hierarchy inferiors to this name (that is, this name followed by the hierarchy delimiter and additional name characters). LATT_NOSELECT this is not a mailbox name, just a hierarchy level, and it may not be opened by mail_open() LATT_MARKED this mailbox may have recent messages LATT_UNMARKED this mailbox does not have any recent messages void mm_notify (MAILSTREAM *stream,char *string,long errflg); stream stream where event happened string message string errflg message error level This function is called to deliver a stream-oriented message event. This is the mechanism by which any IMAP response codes for any application (e.g. TRYCREATE) are delivered to the application. No newline is included in the string, so this function has to output its own. The message error level is one of the following: NIL normal operation. The text is `babble' that may be interesting to the user, e.g. the greeting message from a server. WARN A warning event. This event should be displayed to the user. Examples: a mailbox rewrite failed because of disk full, but the previous mailbox contents were recovered. ERROR An error event. This event should be displayed to the user, or at least logged someplace. This type of error shouldn't happen, and so should be called to the attention of support staff. Whatever happened has probably disrupted the user's work. Examples: an untagged BAD from an IMAP server. void mm_log (char *string,long errflg); string message string errflg message error level This function is called to deliver a log message. No newline is included in the string, so this function has to output its own. In general, it is intended that these messages are logged someplace, and possibly shown to the user. The message error level is one of the following: NIL normal operation. The text is `babble' that may be interesting to the user, e.g. "Expunged 3 messages". PARSE An RFC 822 parsing error. Since bogus headers are all-too-common in the real world, these can often be ignored on the "garbage in, garbage out" princple. However, since surprising results can be yielded when trying to parse garbage, this message should be logged somewhere so it can be figured out what happened. WARN A warning event. This event should be displayed to the user. It occurs when an error condition has happened, but c-client knows what to do to recover. Examples: "Can't open read-write, so opening read-only", "Empty mailbox", "Login failed, try again", "Waiting for mailbox to become unlocked", "IMAP protocol error". Although a user should be told about a warning, it's generally not necessary to interrupt the flow of her work (e.g. it's alright to display the warning in a scrolling window, but not necessary to require the user to do anything). ERROR An error event. This event should be displayed to the user, or at least logged someplace. This is a serious error condition occured that aborted the requested operation and possibly also aborted the mail stream. This ranges from normal error conditions such as "Can't open mailbox", "too many login failures, go away" to bizarre conditions such as "Apparent new mail appeared in the mailbox that doesn't look like mail, program aborting". Errors must be called to the user's attention, and probably should require some sort of acknowledgement (e.g. answering a modal panel) before the application proceeds. void mm_dlog (char *string); string message string This function is called to deliver a debugging telemetry message. No newline is included in the string, so this function has to output its own. This is called only when debugging is enabled. void mm_login (NETMBX *mb,char *user,char *pwd,long trial); mb parsed mailbox specification user pointer to where to return user name pwd pointer to where to return password trial number of prior login attempts This function is called to get a user name and password for the given network mailbox. It stores the user name and password in the strings pointed to by the appropriate arguments. The trial argument is the number of attempts to perform the login and is initially zero (e.g. for a default username and password login functionality). It is incremented for each subsequent trial until the maximum number of trials are made. void mm_critical (MAILSTREAM *stream); stream stream where event happened This function is called to alert the application that c-client is about to run some critical code on that stream that may result in a clobbered mail file if it is interrupted. It may be desirable to disable CTRL/C, etc. during this time. void mm_nocritical (MAILSTREAM *stream); stream stream where event happened This function is called to alert the application that c-client is no longer running critical code on that stream that may result in a clobbered mail file if it is interrupted. long mm_diskerror (MAILSTREAM *stream,long errcode,long serious); stream stream where event happened errcode OS error code for disk error serious non-zero if c-client can not undo the operation (and thus must retry to avoid mail file damage) This function is called to alert the application that the c-client has encountered an unrecoverable write error when trying to update the mail file. errcode contains the system error code. If serious is non-zero, then it is probable that the disk copy of the mailbox has been damaged. The return value from this function is the abort flag; if serious is zero and the abort flag is non-zero, the operation is aborted. If the abort flag is zero or if serious was non-zero, a return from this function will retry the failing operation. void mm_fatal (char *string); string message string This function is called from the fatal() routine in the operating system code to notify the main program that it is about to crash. The string contains a reason. At the very minimum, the main program should do something like mm_log (string,ERROR); and then return. No newline is included in the string, so this function has to output its own. Driver interface When writing a new driver for the c-client, you must provide a DRIVER stucture giving a dispatch vector between MAIL and the driver. The DRIVER dispatch vector is described in mail.h. char *name; Name by which the driver is known to c-client. unsigned long flags; Attribute flags for this driver: DR_DISABLE This driver is currently disabled. DR_LOCAL This driver deals with local mailboxes; if this is off it deals with mailboxes over a network. DR_MAIL This driver supports e-mail messages. DR_NEWS This driver supports netnews messages DR_READONLY This driver only allows read-only access; mail_setflag(), mail_expunge(), etc. are no-ops. DR_NOFAST This driver does not implement mail_fetchfast() in a fast way (e.g. it may have to fetch the entire message text over a network to calculate sizes). DR_NAMESPACE This driver accepts and uses namespace format names. DR_LOWMEM This driver is designed for systems with very limited amounts of memory (e.g. DOS) and support routines called by this driver should try not to use much memory. DRIVER *next; Pointer to the next driver which this application supports (or NIL if this is the last driver). Drivers are lunk together via the mail_link() function. DRIVER *driver_valid (char *mailbox); This function returns a pointer to the driver's DRIVER dispatch vector iff this driver accepts the given name as a valid mailbox for this driver. Otherwise, it returns the value of the next driver's driver_valid() or NIL if there is no next driver. In other words, calling driver_valid() for the first driver will return the driver dispatch vector for the driver which supports this type of mailbox. void *driver_parameters (long function,void *value); This function implements mail_parameters() for this driver. void driver_scan (MAILSTREAM *stream,char *ref,char *pat,char *contents); This function implements mail_scan() for this driver. void driver_list (MAILSTREAM *stream,char *ref,char *pat); This function implements mail_list() for this driver. void driver_lsub (MAILSTREAM *stream,char *ref,char *pat); This function implements mail_lsub() for this driver. long driver_subscribe (MAILSTREAM *stream,char *mailbox); This function implements mail_subscribe() for this driver. long driver_unsubscribe (MAILSTREAM *stream,char *mailbox); This function implements mail_unsubscribe() for this driver. long driver_create (MAILSTREAM *stream,char *mailbox); This function implements mail_create() for this driver. long driver_delete (MAILSTREAM *stream,char *mailbox); This function implements mail_delete() for this driver. long driver_rename (MAILSTREAM *stream,char *old,char *new); This function implements mail_rename() for this driver. long driver_status (MAILSTREAM *stream,char *mailbox,long flags); This function implements mail_status() for this driver. MAILSTREAM *driver_open (MAILSTREAM *stream); This function opens the mailbox identified by the given stream. It may use the data on the stream and create additional data on stream->local as necessary. It should return the given stream unless it failed to open the mailbox, in which case it should return NIL. void driver_close (MAILSTREAM *stream,long options); This function implements mail_close() for this driver. void driver_fetchfast (MAILSTREAM *stream,char *sequence,long flags); This function implements mail_fetchfast() for this driver. void driver_fetchflags (MAILSTREAM *stream,char *sequence,long flags); This function implements mail_fetchflags() for this driver. ENVELOPE *driver_fetchstructure (MAILSTREAM *stream,unsigned long msgno, BODY **body,long flags); This function implements mail_fetchstructure() for this driver. char *driver_fetchheader (MAILSTREAM *stream,unsigned long msgno, STRINGLIST *lines,unsigned long *len,long flags); This function implements mail_fetchheader() for this driver. char *driver_fetchtext (MAILSTREAM *stream,unsigned long msgno, unsigned long *len,long flags); This function implements mail_fetchtext() for this driver. char *driver_fetchbody (MAILSTREAM *stream,unsigned long msgno,char *section, unsigned long *len,long flags); This function implements mail_fetchbody() for this driver. void driver_setflag (MAILSTREAM *stream,char *sequence,char *flag,long flags); This function implements mail_setflag() for this driver. void driver_clearflag (MAILSTREAM *stream,char *sequence,char *flag, long flags); This function implements mail_clearflag() for this driver. void driver_search (MAILSTREAM *stream,char *charset,SEARCHPGM *pgm, long flags); This function implements mail_search() for this driver. unsigned long *driver_sort (MAILSTREAM *stream,char *charset,SEARCHPGM *spg, SORTPGM *pgm,long flags); This function implements mail_sort() for this driver. void *driver_thread (MAILSTREAM *stream,char *seq,long function,long flag); This dispatch is reserved for a future threading capability. long driver_ping (MAILSTREAM *stream); This function implements mail_ping() for this driver. void driver_check (MAILSTREAM *stream); This function implements mail_check() for this driver. void driver_expunge (MAILSTREAM *stream); This function implements mail_expunge() for this driver. long driver_copy (MAILSTREAM *stream,char *sequence,char *mailbox, long options); This function implements mail_copy() for this driver. long driver_append (MAILSTREAM *stream,char *mailbox,char *flags,char *date, STRING *message); This function implements mail_append() for this driver. void driver_gc (MAILSTREAM *stream,long gcflags); This function implements mail_gc() for this driver. Driver Support Functions void mail_searched (MAILSTREAM *stream,unsigned long msgno); stream stream where event happened msgno message number This function is called by the driver to notify c-client that this message number matches a search. It invokes the main program's mm_searched() function. void mail_exists (MAILSTREAM *stream,unsigned long nmsgs); stream stream where event happened nmsgs number of messages This function is called by the driver to notify c-client that this message number exists (i.e. there are this many messages in the mailbox). It invokes the main program's mm_exists() function. void mail_recent (MAILSTREAM *stream,unsigned long recent); stream stream where event happened recent number of messages This function is called by the driver to notify c-client that this many messages are "recent" (i.e. arrived in the mailbox since the previous time the mailbox was opened). void mail_expunged (MAILSTREAM *stream,unsigned long msgno); stream stream where event happened msgno number of messages This function is called by the driver to notify MAIL that this message number has been expunged from the mail file and that all subsequent messages are now referenced by a message number one less than before. It invokes the main program's mm_expunged() function. void mail_lock (MAILSTREAM *stream); stream stream where event happened This function sets the stream lock. It is an error to set the stream lock if the stream is already locked. This is mainly used to catch errors due to a callback function (e.g. mm_exists) inadvertantly recursing back to the MAIL routines and establishing an infinite recursion. Normally, drivers will set the lock prior to calling one of the callback functions above or, more likely, in the beginning of the driver's non-reentrant "do operation" section. In the IMAP4 driver, the stream lock is set when entering imap_send() and cleared on exit. void mail_unlock (MAILSTREAM *stream); stream stream where event happened This function releases the stream lock. It is an error to release the stream lock if the stream is not locked. formats.txt000064400000021646152527400360006775 0ustar00/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ Mailbox Format Characteristics Mark Crispin 11 December 2006 When a mailbox storage technology uses local files and directories directly, the file(s) and directories are layed out in a mailbox format. I. Flat-File Formats In these formats, a mailbox and all the messages inside are a single file on the filesystem. The mailbox name is the name of the file in the filesystem, relative to the user's "mail home directory." A flat-file format mailbox is always a file, never a directory. This means that it is impossible to have a flat-file format mailbox that has inferior mailbox names under it (so-called "dual-usage" mailboxes). For some inexplicable reason, some people want this. The mail home directory is usually the same as the user login home directory if that concept is meaningful; otherwise, it is some other default directory (e.g. "C:\My Documents" on Windows 98). This can be redefined by modifying the c-client source code or in an application via the SET_HOMEDIR mail_parameters() call. For example, a mailbox named "project" is likely to be found in the file "project" in the user's home directory. Similarly, a mailbox named "test/trial1" (assuming a UNIX system) is likely to be found in the file "trial1" in the subdirectory "test" in the user's home directory. Note that the name "INBOX" has special semantics and rules, as described in the file naming.txt. The following flat-file formats are supported by c-client as of the time of this writing: . unix This is the traditional UNIX mailbox format, in use for nearly 30 years. It uses a line starting with "From " to indicate start of message, and stores the message status inside the RFC822 message header. unix is not particularly efficient; the entire mailbox file must be read when the mailbox is open, and when reading message texts it is necessary to convert the newline convention to Internet standard CR LF form. unix preserves UIDs, and allows the creation of keywords. Only one process may have a unix-format mailbox open read/write at a time. . mmdf This is the format used by the MMDF mailer. It uses a line consisting of 4 (0x01) characters to indicate start and end of message. Optionally, there may also be a unix format "From " line. It otherwise has the same characteristics as unix format. . mbx This is the current preferred mailbox format. It can be handled quite efficiently by c-client, without the problems that exist with unix and mmdf formats. Messages are stored in Internet standard CR LF format. mbx permits shared access, including shared expunge. It preserves UIDs, and allows the creation of keywords. . mtx This is supported for compatibility with the past. This is the old Tenex/TOPS-20 mail.txt format. It can be handled quite efficiently by c-client, and has most of the characteristics of mbx format. mtx is deficient in that it does not support shared expunge; it has no means to store UIDs; and it has no way to define keywords except through an external configuration file. . tenex This is supported for compatibility with the past. This is the old Columbia MM format. This is similar to mtx format, only it uses UNIX-style bare-LF newlines instead of CR LF newlines, thus incurring a performance penalty for newline conversion. . phile This is not strictly a format. Any file which is not in a recognized format is in phile format, which treats the entire contents of the file as a single message. II. File/Message Formats In these formats, a mailbox is a directory, and each the messages inside are separate files inside the directory. The file names of these files are generally the text form of a number, which also matches the UID of the message. In the case of mx, the mailbox name is the name of the directory in the filesystem, relative to the user's "mail home directory." In the case of news and mh, the mailbox name is in a separate namespace as described in the file naming.txt. A file/message format mailbox is always a directory. This means that it is possible to have a file/message format mailbox that has inferior mailbox names under it (so-called "dual-usage" mailboxes). For some inexplicable reason, some people want this. Note that the name "INBOX" has special semantics and rules, as described in the file naming.txt. The following file/message formats are supported by c-client as of the time of this writing: . mx This is an experimental format, and may be removed in a future release. An mx format mailbox has a .mxindex file which holds the message status and unique identifiers. Messages are stored in Internet standard CF LF form, so the file size of the message file equals the size of the message. mx is somewhat inefficient; the entire directory must be read and each file stat()'d. We found it intolerable for a moderate sized mailbox (2000 messages) and have more or less abandoned it. . mh This is supported for compatibility with the past. This is the format used by the old mh program. mh is very inefficient; the entire directory must be read and each file stat()'d, and in order to determine the size of a message, the entire file must be read and newline conversion performed. mh is deficient in that it does not support any permanent flags or keywords; and has no means to store UIDs (because the mh "compress" command renames all the files, that's why). . news This is an export of the local filesystem's news spool, e.g. /var/spool/news. Access to mailboxes in news format is read only; however, message "deleted" status is preserved in a .newsrc file in the user's home directory. There is no other status or keywords. news is very inefficient; the entire directory must be read and each file stat()'d, and in order to determine the size of a message, the entire file must be read and newline conversion performed. news is deficient in that it does not support permanent flags other than deleted; does not support keywords; and has no expunge. Soapbox on File/Message Formats If it sounds from the above descriptions that we're not putting too much effort into file/message formats, you are correct. There's a general reason why file/message formats are a bad idea. Just about every filesystem in existance serializes file creation and deletions because these manipulate the free space map. This turns out to be an enormous problem when you start creating/deleting more than a few messages per second; you spend all your time thrashing in the filesystem. It is also extremely slow to do a text search through a file/message format mailbox. All of those open()s and close()s really add up to major filesystem thrashing. What about Cyrus and Maildir? Both formats are vulnerable to the filesystem thrashing outlined above. The Cyrus format used by CMU's Cyrus server (and Esys' server) has a special associated flat file in each directory that contains extensive data (including pre-parsed ENVELOPEs and BODYSTRUCTUREs) about the messages. Put another way, it's a (considerably) more featureful form of mx. It also uses certain operating system facilities (e.g. file/memory mapping) which are not available on older systems, at a cost of much more limited portability than c-client. These considerably ameliorate the fundamental problems with file/message formats; in fact, Cyrus is halfway to being a database. Rather than support Cyrus format in c-client, you should run Cyrus or Esys if you want that format. The Maildir format used by qmail has all of the performance disadvantages of mh noted above, with the additional problem that the files are renamed in order to change their status so you end up having to rescan the directory frequently to locate the current names (particularly in a shared mailbox scenario). It doesn't scale, and it represents a support nightmare; it is therefore not supported in the official distribution. Maildir support code for c-client is available from third parties; but, if you use it, it is entirely at your own risk (read: don't complain about how poorly it performs or bugs). So what does this all mean? A database (such as used by Exchange) is really a much better approach if you want to move away from flat files. mx and especially Cyrus take a tenative step in that direction; mx failed mostly because it didn't go anywhere near far enough. Cyrus goes much further, and scores remarkable benefits from doing so. However, a well-designed pure database without the overhead of separate files would do even better. calendar.txt000064400000035422152527400360007070 0ustar00/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ ALL ABOUT CALENDARS Although one can never be sure of what will happen at some future time, there is strong historical precedent for presuming that the present Gregorian calendar will still be in effect within the useful lifetime of the IMAP toolkit. We have therefore chosen to adhere to these precedents. The purpose of a calendar is to reckon time in advance, to show how many days have to elapse until a certain event takes place in the future, such as the harvest or the release of a new version of Pine. The earliest calendars, naturally, were crude and tended to be based upon the seasons or the lunar cycle. ANCIENT CALENDARS The calendar of the Assyrians, for example, was based upon the phases of the moon. They knew that a lunation (the time from one full moon to the next) was 29 1/2 days long, so their lunar year had a duration of 354 days. This fell short of the solar year by about 11 days. (The exact time for the solar year is approximately 365 days, 5 hours, 48 minutes, and 46 seconds.) After 3 years, such a lunar calendar would be off by a whole month, so the Assyrians added an extra month from time to time to keep their calendar in synchronization with the seasons. The best approximation that was possible in antiquity was a 19-year period, with 7 of these 19 years having 13 months (leap months). This scheme was adopted as the basis for the lunar calendar used by the Hebrews. The Arabs also used this calendar until Mohammed forbade shifting from 12 months to 13 months; this causes the Muslim holy month of Ramadan to move backwards through the seasons, completing a cycle every 32 1/2 years. When Rome emerged as a world power, the difficulties of making a calendar were well known, but the Romans complicated their lives because of their superstition that even numbers were unlucky. Hence their months were 29 or 31 days long, with the exception of February, which had 28 days. Every second year, the Roman calendar included an extra month called Mercedonius of 22 or 23 days to keep up with the solar year. JULIAN CALENDAR Even this algorithm was very poor, so that in 45 BCE, Caesar, advised by the astronomer Sosigenes, ordered a sweeping reform. By imperial decree, the year 46 BCE was made 445 days long to bring the calendar back in step with the seasons. The new calendar, similar to the one we now use was called the Julian calendar (named after Julius Caesar). Months in the Julian calendar were 30 or 31 days in length and every fourth year was made a leap year (having 366 days) by adding a day to the end of the year. This leap year rule was not consistantly applied until 8 CE. The year-ending month of February, never a popular month, was presently shortened so that Julius Caesar and Emperor Augustus could each have long months named after them. Caesar also decreed that the year would start with the first of January, which since 153 BCE was the day that Roman consuls took office, and not the vernal equinox in late March. Not everyone accepted that part of his reform, as we shall see. GREGORIAN CALENDAR Caesar's year was 11 1/2 minutes short of the calculations recommended by Sosigenes and eventually the date of the vernal equinox began to drift. Roger Bacon became alarmed and sent a note to Pope Clement IV, who apparently was not impressed. Pope Sixtus IV later became convinced that another reform was needed and called the German astronomer, Regiomontanus, to Rome to advise him. Unfortunately, Regiomontanus died of the plague shortly thereafter and the plans died as well. In 1545, the Council of Trent authorized Pope Gregory XIII to reform the calendar once more. Most of the mathematical work was done by Father Christopher Clavius, S.J. The immediate correction that was adopted was that Thursday, October 4, 1582 was to be the last day of the Julian calendar. The next day was Friday, with the date of October 15. For long range accuracy, a formula suggested by the Vatican librarian Aloysius Giglio was adopted. It said that every fourth year is a leap year except for century years that are not divisible by 400. Thus 1700, 1800 and 1900 would not be leap years, but 2000 would be a leap year since 2000 is divisible by 400. This rule eliminates 3 leap years every 4 centuries, making the calendar sufficiently correct for most ordinary purposes. This calendar is known as the Gregorian calendar and is the one that we now use today. It is interesting to note that in 1582, all the Protestant princes ignored the papal decree and so many countries continued to use the Julian calendar until either 1698 or 1752. Britain and its American colonies went from Wednesday, September 2, 1752 to Thursday, September 14. Prior to the changeover, the British used March 25 as the start of the new year. In Russia, it needed the revolution to introduce the Gregorian calendar in 1918. Turkey didn't adopt it until 1927. NUMBERING OF YEARS The numbering of the year is generally done according to an "era", such as the year of a ruler's reign. In about 525, a monk named Dionysius Exiguus suggested that the calculated year of Jesus' birth be designated as year 1 in the Julian calendar. This suggestion was adopted over the next 500 years and subsequently followed in the Gregorian calendar. For the benefit of those who seek religious significance to the calendar millenium, note that year 1 is too late by at least 4 years. Herod the Great, named in the Christian Bible as having all children in Bethlehem put to death in an attempt to kill the infant Jesus, died in 4 BCE. Nothing particularly significant of an historic or religious nature happened in Gregorian year 1; however it has become a worldwide standard as the "common era." In modern times, the terms "CE" (common era) and "BCE" (before common era) are preferred over the earlier (and, as we have seen, less accurate) "AD" (anno Domini, "the year of the Lord") and "BC" (before Christ). The Hebrew lunar calendar begins at 3760 BCE, the year of creation in Jewish tradition. The Muslim lunar calendar begins on July 16, 622, when Mohammed fled from Mecca to Medina. The Japanese, Taiwanese, and North Koreans use the Gregorian calendar, but number the year by political era. In Japan, an era begins when an emperor succeeds to the throne; year 1 of the Heisei era was 1989 when Emperor Akihito ascended to the throne (the first few days of 1989 was year 64 of the Shouwa era). In Taiwan, year 1 is the first full year after the founding of the Republic of China in 1911. In North Korea, year 1 is the year of the Juche (self-reliance) ideal, corresponding to the birth year of founder Kim Il-Sung (1912). Thus, year 2000 is Heisei 12 (Japan), 89th year of the Republic (Taiwan), and Juche 89 (North Korea). FURTHER MODIFICATIONS TO THE GREGORIAN CALENDAR Despite the great accuracy of the Gregorian calendar, it still falls behind very slightly every few years. The most serious problem is that the earth's rotation is slowing gradually. If you are very concerned about this problem, we suggest that you tune in short wave radio station WWV or the Global Positioning System, which broadcasts official time signals for use in the United States. About once every 3 years, they declare a leap second at which time you should be careful to adjust your system clock. If you have trouble picking up their signals, we suggest you purchase an atomic clock (not part of the IMAP toolkit). Another problem is that the Gregorian calendar represents a year of 365.2425 days, whereas the actual time taken for the earth to rotate around the Sun is 365.2421991 days. Thus, the Gregorian calendar is actually 26 seconds slow each year, resulting in the calendar being one day behind every 3,300 or so years (a Y3.3K problem). Consequently, the Gregorian calendar has been modified with a further rule, which is that years evenly divisible by 4000 are not leap years. Thus, the year 4000 will not be a leap year. Or, at least we assume that's what will happen assuming that the calendar remains unchanged for the next 2000 years. The modified Gregorian calendar represents a year of 365.24225 days. Thus, the modified Gregorian calendar is actually 4 seconds slow each year, resulting in the calendar being one day slow every 20,000 or so years. So there will be a Y20K problem. There is some dispute whether the modified Gregorian calendar was officially adopted, or if it's just a proposal. Other options (see below) exist; fortunately no decision needs to be made for several centuries yet. There is code in c-client to support the modified Gregorian calendar, although it is currently disabled. Sometime in the next 2000 years, someone will need to enable this code so that c-client is Y4K compiliant. Then, 18,000 years from now, someone will have to tear into c-client's code to fix the Y20K bug. EASTERN ORTHODOX MODIFICATION OF THE GREGORIAN CALENDAR The Eastern Orthodox church in 1923 established its own rules to correct the Julian calendar. In their calendar, century years modulo 900 must result in value of 200 or 600 to be considered a leap year. Both the Orthodox and Gregorian calendar agree that the years 2000 and 2400 will be leap years, and the years 1900, 2100, 2200, 2300, 2500, 2600, 2700 are not. However, the year 2800 will be a leap year in the Gregorian calendar but not in the Orthodox calendar; similarly, the year 2900 will be a leap year in the Orthodox calendar but not in the Gregorian calendar. Both calendars will agree that 3000 and 3100 are leap years, but will disagree again in 3200 and 3300. There is code in c-client to support the Orthodox calendar. It can be enabled by adding -DUSEORTHODOXCALENDAR=1 to the c-client CFLAGS, e.g. make xxx EXTRACFLAGS="-DUSEORTHODOXCALENDAR=1" The Orthodox calendar represents a year of 365.24222222... days. Thus, the Orthodox calendar is actually 2 seconds slow each year, resulting in the calendar being one day slow every 40,000 or so years. The Eastern Orthodox church has not yet made any statements on how the Y40K bug will be fixed. OTHER ISSUES AFFECTING THE CALENDAR IN THE FUTURE The effect of leap seconds also needs to be considered when looking at the Y3.3K/Y4K, Y20K, and Y40K problems. Leap seconds put the clock back in line with the Earth's rotation, whereas leap years put the calendar back in line with the Earth's revolution. Since leap seconds slow down the clock (and hence the calendar), they actually bring the day of reckoning for the Gregorian and Orthodox calendars sooner. Another factor is that the next ice age (technically, the end of the current interglacial period; we are in the middle of an ice age now!) is due around Y25K. It is not known what perturbations this will cause on the Earth's rotation and revolution, nor what calendar adjustments will be necessary at that time. Hence my use of "or so" in predicting the years that the calendar will fall behind. The actual point may be anywhere from decades (in the case of Y3.3K) to millenia (in the case of Y40K) off from these predictions. MEANINGS OF DAY NAMES The names of days of the week from a combination of Roman and Germanic names for celestial bodies: . Sunday Latin "dies solis" => "Sun's day" . Monday Latin "dies lunae" => "Moon's day" . Tuesday Germanic "Tiw's day" => "Mars' day" . Wednesday Germanic "Woden's day" => "Mercury's day" . Thursday Germanic "Thor's day" => "Jupiter's day" . Friday Germanic "Frigg's day" => "Venus' day" . Saturday Latin "dies Saturni" => "Saturn's day" MEANINGS OF MONTH NAMES The names of the months are from the Roman calendar: . January Janus, protector of doorways . February Februalia, a time for sacrifice to atone for sins . March Mars, god of war . April Latin "aperire" => "to open" buds . May Maia, goddess of plant growth . June Latin "juvenis" => "youth" . July Julius Caesar . August Augustus Caesar . September Latin "septem" => "seven" . October Latin "octo" => "eight" . November Latin "novem" => "nine" . December Latin "decem" => "ten" As you'll notice, the last four months are numbered 7 to 10, which is an artifact of the time when the new year started in March. INTERESTING FORMULAE There's another reason why the historical starting of the new year is significant. Starting with March, the length of months follows a mathematical series: 31 30 31 30 31 31 30 31 30 31 31 28 This means that you can calculate the day of week for any arbitrary day/month/year of the Gregorian calendar with the following formula (note all divisions are integral): _ _ | 7 + 31*(m - 1) y y y | dow = | d + -------------- + y + - - --- + --- | MOD 7 |_ 12 4 100 400_| where d := day of month (1..31) m := month in old style (March = 1..February = 12) y := year in old style dow := day of week (Tuesday = 0..Monday = 6) To convert from new style month/year to old style: if (m > 2) m -= 2; /* Mar-Dec: subtract 2 from month */ else m += 10,y--; /* Jan-Feb: months 11 & 12 of previous year */ Here's another fun formula. To find the number of days between two days, calculate a pair of calendar days with the formula (again, all divisions are integral), using new style month/year this time: m m + - 8 y y y d + 30 * (m - 1) + ----- + y * 365 + - - --- + --- - ld 2 4 100 400 where: d := day of month (1..31) m := month in new style (January = 1..December = 12) y := year in new style ld := leap day correction factor: 0 for January and February in non-leap years 1 for January and February in leap years 2 for all other months in all years In C code, the leap day correction factor is calculated as: (m < 3) ? !(y % 4) && ((y % 100) || !(y % 400)) : 2 It's up to you to figure out how to adapt these formulas for the Y4K bugfix and the Orthodox calendar. If you're really clever, try to use these formulae to implement the C library ctime(), gmtime(), and mktime() functions. Most C library implementations use a table of the number of days in a month. You don't need it. ACKNOWLEDGEMENT: The original version is from an old Digital Equipment Corporation SPR answer for VMS. Modifications for c-client, and additional information added by Mark Crispin. drivers.txt000064400000017070152527400360006774 0ustar00/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ c-client Driver Characteristics Mark Crispin 11 December 2006 Drivers are code modules that support different mailbox storage technologies. A mailbox storage technology may be implemented by 1) files and directories on the local system 2) a database 3) a network protocol. In the case of files and directories on the local system, a driver supports a particular mailbox format. Mailbox formats are discussed in more detail in the file formats.txt. As of the date this document was written, there was no bundled support for any databases in c-client. However, it should not be particularly difficult to write a driver that communicates with a database. Network protocols supported by c-client drivers are the Internet Mail Access Protocol (all versions: IMAP4rev1, IMAP4, IMAP2bis, and IMAP2); the Post Office Protocol (version 3); and the Network News Transport Protocol (NNTP). In addition, c-client also supports NNTP and the Simple Mail Transport Protocol (SMTP) for mailbox transport. By default, all drivers are enabled. There is little benefit to be gained by disabling a driver, with one exception. The mbox driver implements the behavior of automatically moving new mail from the spool directory to the "mbox" file on the user's home directory, if and *only* if the "mbox" exists and is in mailbox format. The mbox driver is listed under EXTRADRIVERS; if you wish to disable it just remove it from that list and rebuild. I. Special name "INBOX" The following rules to select INBOX and its format apply in the order given if "black box mode" is not in effect: 1) mbox format is selected if file ~/mbox exists, and is in unix format or is zero-length. 2) mx format is selected if file ~/INBOX/.mxindex exists. 3) mbx format is selected if file ~/INBOX exists and is in mbx format. 4) tenex format is selected if: a) file ~/mail.txt exists, and is in tenex format or is zero-length. b) file ~/INBOX exists and is in tenex format. 5) mtx format is selected if: a) file ~/INBOX.MTX exists, and is in mtx format or is zero-length. b) file ~/INBOX exists and is in mtx format. 6) mmdf format is selected if the spool directory file exists and is in mmdf format. 7) unix format is selected if the spool directory file exists and is in unix format. 8) the dummy driver is selected if the spool directory file does not exist, or exists and is empty. If "black box mode" is not in effect, messages are automatically transferred ("snarfed") from the spool directory to an INBOX in mbox, mx, mbx, tenex, and mtx formats. The following rules to select INBOX and its format apply in the order given if "black box mode" is in effect: 1) mx format is selected if file ~/INBOX/.mxindex exists. 2) mbx format is selected if file ~/INBOX exists and is in mbx format. 3) tenex format is selected if file ~/INBOX exists and is in tenex format. 4) mtx format is selected if file ~/INBOX exists and is in mtx format. 5) mmdf format is selected if file ~/INBOX exists and is in mmdf format. 6) unix format is selected if file ~/INBOX exists and is in unix format. 7) the dummy driver is selected if ~/INBOX does not exist, or exists and is empty. II. Special Name #mhinbox #mhinbox always refers to the directory "inbox" in the MH path, which is declared in the ~/.mh_profile file. Messages are automatically transferred from the spool directory to #mhinbox mailbox. III. Special Prefix "#mh/" Any name prefixed with "#mh/" always refers to a directory in the MH path, which is declared in the ~/.mh_profile file. For example, the name "#mh/foo" refers to directory "foo" in the MH path. IV. Special prefix "#news." Any name prefixed with "#news" always refers to a newsgroup. For example, the name "#news.comp.mail.misc" refers to newsgroup "comp.mail.misc". V. All Other Names The driver is selected by generating a file name from the mailbox name, and then examining the data of the object with the resulting name. The formats are checked in order: mx, mbx, tenex, mtx, mmdf, unix, and phile. The dummy driver is selected if the file is empty. The file name is generated according to certain rules, based upon the prefix of the mailbox name. On UNIX, the following rules apply: Prefix Interpretation of Suffix ------ ------------------------ / [black box] preceeds a user name; "/foo/bar" means "black box user foo's mailbox bar" [not black box] preceeds an absolute path name. ~ [not black box] preceeds a user name; "~foo/bar" means "UNIX user foo's mailbox bar" #ftp/ preceeds UNIX user ftp's mailbox name #public/ preceeds UNIX user imappublic's mailbox name #shared/ preceeds UNIX user imapshared's mailbox name All other names are interpreted in the context of the UNIX user's home directory (not black box), the black box user's black box directory (black box), or UNIX user ftp's home directory (anonymous). The strings "..", "//", and /~ are forbidden in names in: black box mode #ftp, #public, or #shared names anonymous users Anonymous users may only access: INBOX (belonging to UNIX user ftp) files in or below UNIX user ftp's home directory #ftp, #news, and #public namespace VI. Driver Comparison The following information about the local file drivers is an elaboration of a table compiled by Osma Ahvenlampi. Driver CA CE UID Kwd Sub NFS Performance Layout ------ -- -- --- --- --- --- ----------- ------ unix no no yes yes no limited fair file ;;; traditional UNIX format mbox no no yes yes no limited fair file ;;; traditional UNIX format, INBOX only, using ~/mbox with automatic ;;; moving from the mail spool directory. mmdf no no yes yes no limited fair file ;;; default on SCO systems mbx yes yes yes yes no no very good prefile ;;; best performing local file driver; preferred format at UW tenex yes no no limited no no good prefile ;;; compatible with UNIX MM mtx yes no no limited no no very good prefile ;;; PC Pine standard format; compatible with TOPS-20; identical to tenex ;;; but instead CRLF newlines instead of LF mx yes buggy yes yes yes no poor ixdir ;;; fullest function; *not* recommended due to performance problems and bugs; ;;; to be redesigned/rewritten mh yes no no no yes yes very poor dir ;;; compatible with mh; #mhinbox for INBOX, #mh/ prefix for all other names news yes no yes no yes yes very poor ixdir ;;; local news spool access; #news. prefix for all names phile no no no no no yes good file ;;; reads arbitrary file as a single readonly message IMPORTANT: the "performance" ratings are relative to other drivers, and not necessarily to other software which implements those formats. They relate to the driver's performance in typical operations such as an IMAP "FETCH ALL". Key to headings: CA: concurrent read/write access CE: expunge permitted in concurrent read/write access UID: sticky UIDs Kwd: keyword flags Sub: subfolders NFS: usable over network filesystems (NFS, AFS, etc.) Layout: file - single file prefile - file with preallocated space for state dir - directory, messages are files ixdir - directory, messages are files, with helper index In addition, drivers imap, nntp, and pop3 support IMAP4rev1, NNTP, and POP3 protocols respectively. imaprc.txt000064400000064757152527400360006607 0ustar00/* ======================================================================== * Copyright 1988-2006 University of Washington * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * * ======================================================================== */ .imaprc secrets revealed! Mark Crispin, June 17, 2002 The following information describes the format of the /etc/c-client.cf and ~/.imaprc file. The Columbia MM ~/.mminit file is also read by c-client; however, the only command that ~/.mminit has in common is set keywords. ********************************************************************** * DANGER! BEWARE! TAKE CARE! * ********************************************************************** * * * These files, and this documentation, are for internal UW usage * * only. This capability is for UW experimental tinkering, and most * * emphatically *not* for sorcerer's apprentices at other sites who * * feel that if a config file capability exists, they must write a * * config file whether or not there is any need for one. * * * * This information is subject to change without notice. Commands * * may be added, removed, or altered. The behavior of comamnds may * * change. Do not use any of this information without consulting me * * first. c-client's defaults have been carefully chosen to be right * * for general-purpose and most special-purpose configurations. If * * you tinker with these defaults, all hell may break loose. * * * * This is not an idle threat. There have been several instances of * * people who ignored these warnings and have gotten burned. * * * * Don't even trust this file to work. Many of the things which can * * be changed by this file can also be changed by the application, * * and it is totally unpredictable which will take precedence. It * * all depends upon how the application is coded. Not only that, you * * may cause the application to crash. * * * * In other words, keep your cotton-pickin' hands off my defaults. * * If it crashes and erases your mail, I don't want to hear about it. * * Consider 'em ``mandatory defaults''. Got a nice ring, eh? :-) If * * you must tinker with defaults, play with the .pinerc and pine.conf * * files in Pine. It's got options galore, all supported for you to * * have fun. They're also documented; so well documented, it takes * * two strong men to carry around all the documentation. ;-) ;-) * * * * Joking aside, you really shouldn't be fooling around with this * * capability. It's dangerous, and you can shoot yourself in the * * foot easily. If you need custom changes, you are better off with * * local source code modifications. Seriously. * * * * One last warning: don't believe anything that you read in this * * document. Every effort has been made to ensure that this document * * is incomplete and inaccurate, and I take no responsibility for any * * glimmers of correct information that may, by some fluke, be here. * * * ********************************************************************** The files are read in order: /etc/c-client.cf, ~/.mminit, ~/.imaprc, and an entry in a later file overrides the setting of an earlier file except as noted below. This ordering and overriding behavior may change without notice. Almost all of these facilities can also be set via the mail_parameters() call in the program. Whether the file overrides mail_parameters(), or mail_parameters() overrides the file, is indeterminate. It will vary from program to program, and it may be one way in one version and the other way in the next version. It's completely unpredictable, and so anything you do with these files has to be in complete knowledge of what the version of each program you're running is going to do. This is because the files do something for testing, but the real capability for configurability is put in the program instead. Are you getting the feeling that you shouldn't be messing with these files yet? The very first line of the file MUST start with the exact string "I accept the risk". This ensures that you have checked the file for correctness against this version of the IMAP toolkit. This enable string may change without notice in future versions, and the new string may or may not be accurately described in an updated version of this file. So any time you install software that uses the IMAP toolkit, you need to check the new version against these files (if you have insisted upon creating them in spite of all warnings). If two pieces of software use different versions of the IMAP toolkit with incompatible requirements, one of them won't work. Re-read the warning above about why you should not use these files. Subsequent lines are read from the file one at a time. Case does not matter. Unrecognized commands are ignored. 1) set new-folder-format sets what format new mailboxes are created in. This also controls default delivery via tmail and dmail. a) set new-folder-format same-as-inbox Folder is created using the same mailbox format as INBOX. If INBOX is empty, it defaults to system standard. b) set new-folder-format system-standard This is the default. Folder is created using the wired-in system standard format, which on most UNIX systems is ordinary UNIX /bin/mail format. On SCO systems, this is MMDF. c) set new-folder-format Folder is created using the given driver name, e.g. mbx, unix, mmdf, etc. There is no protection against setting this to a silly value (e.g. news, nntp, dummy) and doing so is a great way to screw things up. Setting this to mh does not do what you think it does. Setting this to tenex or mtx isn't particularly useful. 2) set empty-folder-format sets what format data is written into an empty mailbox file using mail_copy() or mail_append(). This also controls default delivery via tmail. a) set empty-folder-format same-as-inbox Data is written using the same mailbox format as INBOX. If INBOX is empty, it defaults to system standard. b) set empty-folder-format system-standard This is the default. Data is written using the wired-in system standard format, which on most UNIX systems is ordinary UNIX /bin/mail format. On SCO systems, this is MMDF. c) set-empty-folder-format Data is written using the given driver name, e.g. tenex, unix, mmdf, etc. There is no protection against setting this to a silly value (e.g. news, nntp, dummy) and doing so is a great way to screw things up. Setting this to mh, mbx, or mx does not work. 3) set keywords , , ... Sets the list of keyword flags (supported by tenex and mtx) to the given list. Up to 30 flags may be given. Since these names correspond to numeric bits, the order of the keywords can not be changed, nor can keywords be removed or inserted (you can append new keywords, up to the limit of 30). Set keywords is a deprecated command. It may not appear in future versions, or it may appear in a changed form. It exists only for compatibility with MM, and should only appear in ~/.mminit and not in the other files. It is likely to disappear entirely in IMAP4. There is no protection against setting these to silly values, and doing so is a great way to cause a crash. 4) set from-widget header-only Sets smart insertion of the > character in front of lines that begin with ``From ''. Only such lines that are also in UNIX mbox header file format will have a > character inserted. The default is to insert the > character in front of all lines which begin with ``From '', for the benefit of legacy tools that get confused otherwise. 5) set black-box-directory Sets the directory in which the user's data can be found. A user's folders can be found in a subdirectory of the black box directory named with the user's username. For example, if the blackbox directory is /usr/spool/folders/, user jones' data can be found in /usr/spool/folders/jones/. The user's black-box directory is the location of folders, .mminit, .imaprc, .newsrc, and all other files used by c-client; internally, it sets c-client's idea of the user's ``home directory'', overriding /etc/passwd. This command may not appear in ~/.mminit or ~/.imaprc In black-box mode, it is not permitted to access any folders outside of the user's personal blackbox directory. The breakouts ``/'', ``~'', and ``..'' are not permitted. In order to make this work without crashing, you must set another option which is not listed in this document. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 6) set local-host Sets c-client's idea of the local host name. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 7) set news-active-file Sets the location of the news active file, if it is not in the standard place. It is recommended to use a courtesy symbolic link instead. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 8) set news-spool-directory Sets the location of the news spool, if it is not in the standard place. It is recommended to use a courtesy symbolic link instead. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 9) set news-state-file Sets the location of the news state file (normally $(USER)/.newsrc). This is not very useful in /etc/c-client.cf because it is a file name. Setting this in /etc/c-client.cf would set all users to the same file as their newsrc, which is probably not what you want. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 10) set system-inbox Sets the location of the "system inbox", if it is not in the standard place. This is the default location of INBOX, or the mail drop point from which mail is snarfed (e.g. in tenex, mtx, mbox, mh formats). This is not very useful in /etc/c-client.cf because it is a file name. Setting this in /etc/c-client.cf would set all users to the same file as their system inbox, which is probably not what you want. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 11) set tcp-open-timeout Sets the number of seconds that the TCP routines will block on opening a TCP connection before timing out. If a timeout occurs, the connection attempt is aborted. The default is zero, meaning use the operating system default (75 seconds on most UNIX systems). There is no protection against setting this to an excessively small value, such as 1, and doing so is a great way to cause users extreme grief. 12) set tcp-read-timeout Sets the number of seconds that the TCP routines will block on reading data before calling the timeout routine. If no timeout routine is set by the program, the connection will be aborted on a timeout. The default is zero, meaning infinite. There is no protection against setting this to an excessively small value, such as 1, and doing so is a great way to cause users extreme grief. 13) set tcp-write-timeout Sets the number of seconds that the TCP routines will block on sending data before calling the timeout routine. If no timeout routine is set by the program, the connection will be aborted on a timeout. The default is zero, meaning infinite. There is no protection against setting this to an excessively small value, such as 1, and doing so is a great way to cause users extreme grief. 14) set rsh-timeout Sets the number of seconds that the rsh routines will block on opening an rimapd connection before timing out. If a timeout occurs, the rsh connection attempt is aborted. A zero timeout will disable rsh. The default is 15 seconds. There is no protection against setting this to an excessively small value, such as 1, and doing so is a great way to cause users extreme grief. 15) set maximum-login-trials Sets the number of iterations of asking the user, via mm_login(), for a user name and password, before cancelling the attempt. The default is 3. There is no protection against setting this to zero, and doing so is a great way to cause users extreme grief. 16) set lookahead Sets the number of envelopes that are looked ahead in IMAP, in mail_fetchstructure(). This is based on the guess that in such operations as drawing browser lines, if you get data for message n you are likely to want it for message n+1, n+2,... in short order. Lookahead preloads the c-client cache and saves unnecessary RTTs. The default is 20, a good number for a browser on a 24x80 screen, and small enough to usually have no significant real-time difference from a single message fetch. Setting it to 0 turns off lookahead. There is no protection against setting this ridiculously high and incurring performance penalties as a result. 17) set prefetch Sets the number of envelops which are automatically fetched for the messages which match in a search. This is based on the guess that in a browser that is "zoomed" on the results of a search, you are likely to want the envelope data for each of those messages in short order. Prefetching reloads the c-client cache, saves unnecessary RTTs, and avoids loading undesired envelopes due to lookahead (see above). The default is 20. Setting it to 0 turns off prefetch. There is no protection against setting this ridiculously high and incurring performance penalties as a result. 18) set close-on-error If non-zero, IMAP connections are closed if an EXAMINE or SELECT command fails. Otherwise, they are left half-open, and can be used again to select some other mailbox. The mailbox name in the stream is set to {serverhost} The default is zero (do not close on error). 19) set imap-port Set the TCP/IP contact port to use for IMAP. This overrides the wired-in setting and the setting from /etc/services, and can in turn be overridden by an explicit user specification in the mailbox name, e.g. {serverhost:143}foo The default is zero (use setting from /etc/services or the wired-in setting (143). There is no protection against setting this to a silly value, and doing so is a great way to cause users extreme grief. 20) set pop3-port Set the TCP/IP contact port to use for POP3. This overrides the wired-in setting and the setting from /etc/services, and can in turn be overridden by an explicit user specification in the mailbox name, e.g. {serverhost:110/pop3} The default is zero (use setting from /etc/services or the wired-in setting (110). There is no protection against setting this to a silly value, and doing so is a great way to cause users extreme grief. 21) set uid-lookahead Sets the number of UIDs that are looked ahead in IMAP in mail_uid(). Lookahead preloads the c-client cache and saves unnecessary RTTs. The default is 1000, small enough to usually have no significant real-time difference from a single message UID fetch. Setting it to 0 turns off lookahead. There is no protection against setting this ridiculously high and incurring performance penalties as a result. 22) set mailbox-protection Set the default protection for newly-created mailbox files. The default is 384. There is no protection against setting this to a silly value, and doing so is a great way to screw things up massively. 23) set directory-protection Set the default protection for newly-created directories. The default is 448. There is no protection against setting this to a silly value, and doing so is a great way to screw things up massively. 24) set lock-protection Set the default protection for lock files The default is 438, which is necessary if locks are to be respected by processes running as other UIDs. There is no protection against setting this to a silly value, and contrary to what you may think just about any value other than 438 turns out to be a silly value. 25) set disable-fcntl-locking This only applies to SVR4 systems. If non-zero, fnctl() locking is not attempted. In the past, this was used to avoid locking NFS files. If NFS is involved, the evil lockd/statd daemons get invoked. These daemons supposedly work over NFS, but really don't. You probably don't really want to do this, though, because now the flock() emulator (which calls fcntl()) now checks to see if the file is accessed via NFS and no-ops the lock. This is compatible with BSD. Disabling fcntl() locking loses a great deal of locking protection on local files as well as NFS files (which now never have locking protection). The default is zero (fcntl() locking is enabled). 26) set lock-EACCES-error If non-zero, a warning message is given if an attempt to create a lock file fails. Otherwise, EACCES is treated as a "silent failure", and it proceeds without trying to use the lock file. This is for the benefit of users on systems with paranoid /usr/spool/mail protections which don't let users create /usr/spool/mail/$(USER).lock files; these unfortunate users would be harassed with a flood of error messages otherwise. The problem is that on SVR4, if EACCES remains disabled and fcntl() locking is also disabled, then there is no locking at all which is doubleplus-ungood. If the site is paranoid on /usr/spool/mail protections AND if there is no fcntl() locking (SVR4) or usable flock() locking (e.g. NFS), then there is no way to win. Find a different system to use. The default is non-zero (report EACCESS as an error). 27) set list-maximum-level Sets the maximum depth of recursion that a * wildcard list will go down the directory tree. 0 means that no recursion is permitted, and * becomes like %. The default is 20. There is no protection against setting this to a ridiculously high value. Since LIST will follow symbolic links, it can effectively recurse infinitely, until the name strings get large enough that some name limit is exceeded. 28) set anonymous-home-directory Sets the location of the anonymous home directory, if it is not in the standard place. It is recommended to use a courtesy symbolic link instead. There is no protection against setting this to a silly value, and doing so is a great way to cause a crash. 29) set chroot-server This option is for closed server systems only. If defined, a chroot() call to the user's home directory is done as part of the login process. This has the effect of preventing access to any files outside of the user's home directory (including shared mailboxes). Shared mailboxes with other users can't possibly work with this option, because there is no way to export lock information to other users. This should be done ONLY on systems which do not permit users to have shell access This option should NEVER(!!) be set if users are allowed shell access. Doing so actually makes the system *less* secure, since the user could create an etc subdirectory which would be treated as real /etc by such programs as /bin/su. The default is zero (don't do chroot). This option is strongly *NOT* recommended. 30) set disable-automatic-shared-namespaces Never look up the "ftp", "imappublic", and "imapshared" users as posssible home directories for the #ftp, #public, and #shared namespaces. On some systems (reportedly including AIX 4.3.3) getpwnam() of an unknown user name is horrendously slow. Note that this does not remove the #ftp, #public, and #shared namespaces, and they can still be set up by other means. The default is zero (shared namespaces are automatic). 31) set advertise-the-world Include the UNIX root as a shared namespace. This is generally a bad idea, since certain IMAP clients (names withheld to protect the guilty) will take this as license to download the entire filesystem tree. The default is zero (don't advertise the world). 32) set mail-subdirectory Change the default connected directory from the user's home directory to the named subdirectory of the user's home directory. For example, setting MAILSUBDIR="mail" will cause the POP2 and IMAP servers to connect to the user's ~/mail subdirectory. This is equivalent to the env_unix.c edit described in Example 2 of the CONFIG file. Note that if the subdirectory does not exist, the result is undefined. It is probably an extremely bad idea to set this unless you can guarantee that the subdirectory exists for all users. If you can not guarantee this, then you should leave the default as the user's home directory and allow them to configure a personal default in their IMAP client. The default is not to use any subdirectory. 33) set allow-user-config Allow users to use ~/.imaprc and ~/.mminit files. The default is zero (don't allow user config files). 34) set allow-reverse-dns By default, the servers (ipop[23]d and imapd) will do gethostbyaddr() on the local and remote sockets so that imapd can identify itself properly (this is important when the same CPU hosts multiple virtual hosts on different IP addresss) and also includes the client's name when it writes to the syslog. There are also client gethostbyaddr() calls, used primarily by authentication mechanisms. Setting this option to zero disables all gethostbyaddr() calls. The returned "host name" string for the socket is just the bracketed [12.34.56.78] form, as if the reverse DNS lookup failed. WARNING: Some authentication mechanisms, e.g. Kerberos V, depend upon the host names being right, and if you set this option, it won't work. You should only do this if you are encountering server performance problems due to a misconfigured DNS, e.g. long startup delays or client timeouts. The default is non-zero (allow reverse DNS). 35) set disable-plaintext Disable plaintext password authentication (LOGIN command, AUTH=LOGIN, and AUTH=PLAIN). The default is zero (allow plaintext authentication). 36) set trust-dns By default, host names are canonicalized via gethostbyname() for everything except for SSL certificate validation. This can represent a security bug due to DNS spoofing, but is more likely to deliver results that users expect. It also may be necessary for SASL authentication to work right (e.g. generating a correct name for a Kerberos service principal) if the name entered by the user is a CNAME or not a fully-qualified domain name. If trust-dns is set to zero, no host name canonicalization is done. The user's actual entered name is used for SASL authentication and will appear in the mailbox name of the open stream. The default is non-zero (do DNS canonicalization). 37) set sasl-uses-ptr-name By default, if trust-dns is set, the host names used in authentication (e.g. to generate a Kerberos service principal) are canonicalized via gethostbyaddr() instead of by gethostbyname(). If gethostbyaddr() fails the gethostbyname() canonicalization is used. This represents an additional security bug due to DNS spoofing, over and above trust-dns. It also adds an additional DNS query to starting a session. It is necessary for sites which implement a server cluster with multiple A records for a cluster name (instead of a CNAME) but each cluster member has a unique PTR record which it expects for a Kerberos service principal. If sasl-uses-ptr-name is set to zero and trust-dns is set non-zero, the gethostbyname() canonicalized name is used for SASL authentication. The setting of sasl-uses-ptr-name is irrelevant if trust-dns is set to zero. The default is non-zero (use name from PTR record for SASL). 38) set network-filesystem-stat-bug By default, traditional UNIX mailbox files are only closed and reopened at checkpoint and expunge time. This ensures that, prior to rewriting the file, that any cached stat() data from a network filesystem is updated with current data. Very old versions of NFS, and reputedly also AFS, can get into a state in which the cached stat() data stays out-of-date, even across a close and reopen of the file. If network-filesystem-stat-bug is set non-zero, then the mailbox file is closed and reopened at ping time as a workaround for this bug in these network filesystems. This means that in imapd, the mailbox file is closed and reopened for every IMAP command. This is obviously something that should be avoided unless absolutely necessary. NFS and AFS are terrible ways to distribute mail. You use use IMAP servers with a local disk instead. The default is zero (only close/reopen at checkpoint and expunge time). Setting this option is a great way to ruin your system's performance. 39) set restrict-mailbox-access