NOTE: New commands added to daemon, with no mention in the help yet... get_user_size user@example.com get_domain_size domain ========================================================================== Vpopmaild provides a way for authorized clients to perform most of the tasks you can do with the vpopmail command line tools, without having to ssh into the server and run them by hand. We are not yet at a point where every function available in vqadmin and qmailadmin is available from the daemon, but that is the plan. This documentation is still rough, but it is a start. It is a combination of the original information provided by Ken Jones, the original author of vpopmaild, a list of functions available by Rick Widmer and some pages from John Simpson's qmail web site: http://qmail.jms1.net/ If you are looking for step by step instructions for setting up a qmail + vpopmail server that includes the daemon, try Bill Shupp's toaster: http://shupp.org/toaster/ Another source of information on the daemain is Inter7's qmail wiki: http://qmailwiki.inter7.com/Vpopmaild The most basic capability of vpopmaild is to verify whether or not a given email address and password are correct. This can be done with the slogin command. Basically, if the slogin command succeeds, the address and password are valid. If not, then they are not valid. You should quit or exit the daemon before you close the connection. Once you are logged in your personal rights will control which commands you can use, and how much of the mail system you can control. The daemon supports creating and deleting domains only for system administrators. Creating addresses, aliasas and such within a domain for system and domain administrators. Anyone can change their password, set up a forward or vacation message. (Try help from various users.) There are at least two projects to replace qmailadmin using the daemon. Rick Widmer has one on SourceForge called pmailadmin. Currently only the daemon interface and system library are operational. http://pmailadmin.sourceforge.net/ Bill Shupp has announced a project, it is currently only available if you email the author. There are five sections to the rest of this document: 1: Using the service 2: Command List 3: Installing the Daemon 4: Bitmap Values 5: Interpreting Errors -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- 1 : U s i n g t h e s e r v i c e If you don't yet have the daemon running, skip down to section 3, Installing the Daemon, and use one of those options to start the daemon. Once the service is running, you can test it by telnetting to localhost port 89. This is a sample of what it looks like when running as a service on port 89. $ telnet localhost 89 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. +OK login userid@domain.xyz p@ssw3rd +OK+ vpopmail_dir /home/vpopmail domain_dir /home/vpopmail/domains/domain.xyz uid 89 gid 89 name userid comment userid quota NOQUOTA user_dir /home/vpopmail/domains/domain.xyz/userid encrypted_password $1$ZXWVRRi9$X.ZdqlNURS32jD4YdkFkq0 clear_text_password no_password_change 0 no_pop 0 no_webmail 0 no_imap 0 bounce_mail 0 no_relay 0 no_dialup 0 user_flag_0 0 user_flag_1 0 user_flag_2 0 user_flag_3 0 no_smtp 0 domain_admin_privileges 0 override_domain_limits 0 no_spamassassin 0 delete_spam 0 system_admin_privileges 0 . quit +OK Connection closed by foreign host. As you can see, when you successfully log into the service, it shows you pretty much everything about the account you are logged into. The clogin command returns the same information, but does not decode the gid_flags bitmap. This reduces the amount of data transferred by about 60%. Think Compact Login. It does this for all commands that return bitmap values for the entire session. If you are writing a program to access the daemon, it is probably easier to decode the bitmap than the lines of text. The bit values are listed in section 4 near the end of this file. $ telnet localhost 89 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. +OK clogin userid@domain.xyz p@ssw3rd +OK+ vpopmail_dir /home/vpopmail domain_dir /home/vpopmail/domains/domain.xyz uid 89 gid 89 name userid comment userid quota NOQUOTA user_dir /home/vpopmail/domains/domain.xyz/userid encrypted_password $1$ZXWVRRi9$X.ZdqlNURS32jD4YdkFkq0 clear_text_password gidflags 196608 . quit +OK Connection closed by foreign host. When all you need to know is if the current login is valid, use the slogin command. Think Silent Login. All this returns is +OK if the user exists and the password is valid or -ERR if either is incorrect. You should send the quit command before you disconnect from the service. $ telnet 127.0.0.1 89 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. +OK login userid@domain.xyz p@ssw3rd +OK quit +OK Connection closed by foreign host. A few things are worth mentioning here... The help command will show you a list of all of the commands that you have permission to use. Help can be used before or after login. There are three kinds of users with increasing commands that they can use. A simple user can change their password, create forwards and mail robots, and maintain a set of .vpopmail-extension files similar to the .qmail-extension capability of qmail-local. If the domain_admin_privileges flag is set to 1, you are able to administer any mailbox within the domain of your account (i.e. if you are logged in as postmaster@domain.xyz you will be able to create, delete, and modify mailboxes within the domain.xyz domain. If the system_admin_privileges flag is set to 1, you are able to administer any mailbox on the system, plus list, add, remove, and otherwise administer entire domains. The various flags associated with each account are manipulated using the mod_user command within the service, or using the vmoduser command line program. For example, to set the domain_admin_privileges flag for an account, you can use the following command: As root... # vmoduser -a postmaster@domain.xyz You can run vmoduser by itself to see the list of flags which can be set. Note that some of the flags may not have any effect on your system, depending on how vpopmail was compiled. Be very careful with the -S option (which sets the system_admin_privileges flag.) If you are going to have user with system admin rights, you might want to create a domain with an illegal name like illegal.xyz vpopmaild will allow you to login, but there is no way to send email to this domain. # vadddomain illegal.xyz postmaster-password # vmoduser -S postmaster@illegal.xyz -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- 2 : C o m m a n d s consider ordering commands from lesser rights to more rights. NOTE: mod_user is the one with the breakdown of the gidflage bitmap. -------------------------------------------------------------------- login user@domain.ext password - verbose user/domain attributes clogin user@domain.ext password - compact user/domain attributes slogin user@domain.ext password - silent, just return success or failure of login Rights required: Must be a valid email address. Action: Verify the username and password of the persion desiring to login, and set their access rights. For the "login" command, a successful login will return a full list of the user's information. For the "clogin" command, a successful login wil return a compact version of the user's information- bitmap values are returned as a single numeric value instead of a line for each bit used. This reduces data transfer, but requires the client to split up the bitmap. For the "slogin" command, a successful login only returns the "+OK " response, with no additional information. This is useful in cases where the client does not need to know anything other than whether or not the login attempt was successful (i.e. for the SMTP AUTH command.) -------------------------------------------------------------------- add_user user@domain.ext password Rights required: SA_ADMIN, or QA_ADMIN Action: Add a new mailbox and user to the specified domain. ONLY SA_ADMIN can add users to domains other than the home domain of the login user. -------------------------------------------------------------------- del_user user@domain.ext Rights required: SA_ADMIN, or QA_ADMIN Action: Delete a mailbox and user from the specified domain. ONLY SA_ADMIN can delete users from domains other than the home domain of the login user. -------------------------------------------------------------------- mod_user user@domain.ext Rights required: Only SA_ADMIN can modify users outside the login user's home domain. Only QA_ADMIN can modify other users. Any user can modify part of their own data. Action: Modify a user account. The mod_user command is followed by any number of the following options, one per line, followed by a line containing only a '.'. Each flag except the clear_all_flags expects a 0 or 1 to set the value of the flag. Anyone can set these values: comment - The full name of the user. clear_text_password - Pass it a clear text password, and it will set both the clear_text_password and the encrypted_password field. It handles encrypting the password internally. no_spamassassin - Do not run SpamAssasin for this user, if it is set to be run for users of this domain. delete_spam - If set, mail identified as spam for this user will be deleted. The QA_ADMIN or SA_ADMIN can change these values: Only a SA_ADMIN or QA_ADMIN with override rights can change these values: quota - Number of messages they can store. clear_all_flags - reset all the following flag values to 0. no_password_change - The user can not change their own password. no_pop - The user can not access mail via pop. no_webmail - The user can not access mail via a webmail program. no_imap - The user can not access mail via imap. bounce_mail - I'm not sure, but it sounds like a flag to bounce all mail to this user. no_relay - I'm not sure, but it sounds like a flag to block use of SMTP for this user for mail leaving the server. no_dialup - This is used by the optional radius server as a flag to stop radius from allowing this user to login to a modem. user_flag_0 - Set and check this flag for anything you want. user_flag_1 - Set and check this flag for anything you want. user_flag_2 - Set and check this flag for anything you want. user_flag_3 - Set and check this flag for anything you want. no_smtp - I'm not sure. domain_admin_privileges - allow this user limited access to their home domain. override_domain_limits - Allow this user to change domain limits on their own domain. Probably also requires domain_admin. Only a SA_ADMIN can change these values: encrypted_password - an already encrypted password. This only sets the encrypted password field. system_admin_privileges - allow this user full access to all domains. system_expert_privileges - allow this user to edit .qmail files. -------------------------------------------------------------------- user_info user@domain.ext Rights required: SA_ADMIN, or QA_ADMIN Action: Return information about a user. The following items are returned as a string. name - User name, same as user part of address selected. comment - Usually the long name of the user. quota - How much disk space the user is allowed. user_dir - The home directory for the user. encrypted_password - The encrypted value of the password. clear_text_password - The password in clear text. The following values are returned as the character '1' or '0'. '1' says the field is active which, for example an active no_password_change means the user can not change passwords. no_password_change, no_pop, no_webmail, no_imap, bounce_mail, no_relay, no_dialup, user_flag_0, user_flag_1, user_flag_2, user_flag_3, no_smtp The following items confer extra privileges to the user. A '1' says that the user has that right. domain_admin_privileges, override_domain_limits, system_admin_privileges The following items control the operation of Spamassassin. no_spamassassin, delete_spam -------------------------------------------------------------------- add_domain domain password Rights required: SA_ADMIN Action: Add a new, real domain. The postmaster user is automatically created, and cannot be deleted. The password given is assigned to the postmaster user. -------------------------------------------------------------------- add_alias_domain domain alias Rights required: SA_ADMIN Action: Add an alias to an existing domain. Qmail will recognize the alias domain name, but all incoming mail to that domain will be sent to the real domain. Currently the order of the parameters must be correct. Consider stealing code from vaddaliasdomain so it doesn't matter what order you enter them in. -------------------------------------------------------------------- del_domain domain Rights required: SA_ADMIN Action: Delete a domain from the system. If the domain is an alias it will delete only the alias. If the domain has aliases, the domain and all of its aliases will be deleted. If you want to warn the user of your program when alias domains exist, YOU will have to do it yourself by using dom_info() to check the status of the domain in question. -------------------------------------------------------------------- dom_info domain Rights required: SA_ADMIN Action: return internal information about a domain. The information returned includes: domain directory, userid, groupid, number of users. If you ask for an alias domain, you will receive information for the parent domain. Part of that information will include a list of all alias names of the parent domain. -------------------------------------------------------------------- find_domain domain per_page Rights required: SA_ADMIN Action: Return the page number that the named domain appears on only if the domain exists. Otherwise, just "." is returned. This can be used when you are using list_domains with the optional page and lines_per_page parameters. If you list the page returned by find_domain, the desired domain will appear on that page. It may not be at the top of the page. The page positions are fixed. If no per_page argument is given, it defaults to one item per_page. Page numbers start at 1. -------------------------------------------------------------------- domain_count Rights required: SA_ADMIN Action: Return the number of domains. This can be used to determine the number of pages of domain information that is available. -------------------------------------------------------------------- user_count domain Rights required: SA_ADMIN, QA_ADMIN. QA_ADMIN can only manage their own domain. Action: Return the number of accounts in a domain. This can be used to determine the number of pages of user account information that is available. -------------------------------------------------------------------- mk_dir directory Rights required: SA_ADMIN, QA_ADMIN or USER. QA_ADMIN can only work within their own domain. USER can only work within their home directory. Action: Create a directory. Directory can be specified as a real path starting at root, as a domain name, or as an email address. When a domain name is specified, that is replaced by the path to the domain directory for that domain. When an email address is specified, that starts at the home directory for that email address. -------------------------------------------------------------------- rm_dir directory Rights required: SA_ADMIN, QA_ADMIN or USER. QA_ADMIN can only work within their own domain. USER can only work within their home directory. Action: Remove a directory Directory can be specified as a real path starting at root, as a domain name, or as an email address. When a domain name is specified, that is replaced by the path to the domain directory for that domain. When an email address is specified, that starts at the home directory for that email address. -------------------------------------------------------------------- list_dir directory Rights required: SA_ADMIN, QA_ADMIN or USER. QA_ADMIN can only work within their own domain. USER can only work within their home directory. Action: List the contents of a directory. Directory can be specified as a real path starting at root, as a domain name, or as an email address. When a domain name is specified, that is replaced by the path to the domain directory for that domain. When an email address is specified, that starts at the home directory for that email address. Directory contents are returned one per line, with an indication of the type of directory entry. For example: Maildir dir lastauth file The possible type values are: file, dir, chardev, blkdev, fifo, link, sock, unknown. -------------------------------------------------------------------- rm_file filename Rights required: SA_ADMIN, QA_ADMIN or USER. QA_ADMIN can only work within their own domain. USER can only work within their home directory. Action: Remove a file. Directory can be specified as a real path starting at root, as a domain name, or as an email address. When a domain name is specified, that is replaced by the path to the domain directory for that domain. When an email address is specified, that starts at the home directory for that email address. -------------------------------------------------------------------- write_file filename Rights required: SA_ADMIN, QA_ADMIN or USER. QA_ADMIN can only work within their own domain. USER can only work within their home directory. Action: Write lines to a file. Filename can be specified as a real path starting at root, as a domain name, or as an email address. When a domain name is specified, it is replaced by the path to the domain directory for that domain. When an email address is specified, that starts at the home directory for the email address. File contents are sent, one line sent to the daemon for each line to add to the file. After the last line send a line containing only a period '.' to mark the end of file. -------------------------------------------------------------------- stat_file filename Rights required: SA_ADMIN, QA_ADMIN or USER. QA_ADMIN can only work within their own domain. USER can only work within their home directory. Action: Stat a file. Filename can be specified as a real path starting at root, as a domain name, or as an email address. When a domain name is specified, it is replaced by the path to the domain directory for that domain. When an email address is specified, that starts at the home directory for the email address. Currently only the UID of the owner of the file is returned if it exists or an error (2202) is returned. It seems to me this should be extended to include at least access rights in octal, size, owner group, last access, last mod, last change. -------------------------------------------------------------------- read_file filename Rights required: SA_ADMIN, QA_ADMIN or USER. QA_ADMIN can only work within their own domain. USER can only work within their home directory. Action: Read lines from a file. Filename can be specified as a real path starting at root, as a domain name, or as an email address. When a domain name is specified, it is replaced by the path to the domain directory for that domain. When an email address is specified, that starts at the home directory for the email address. File contents are received, one line from the daemon for each line in the file. After the last line of the file a line containing only a period '.' is sent to mark the end of file. -------------------------------------------------------------------- list_domains [page lines_per_page] Rights required: SA_ADMIN Action: List all domains on the system, and their parent domain. If the optional page is given, lines_per_page must be specified also. When both are given, the data is broken up into pages with lines_per_page lines on each. The page returned is specified by page. Alias domains are identified by the fact that the domain name does not match the real domain name. -------------------------------------------------------------------- list_users domain [page lines_per_page] Rights required: SA_ADMIN, or QA_ADMIN. QA_ADMIN can only manage their own domain. Action: List all Mailbox accounts for a domain. It returns the same info about a user as something else. Find it and copy the info here. If the optional page is given, lines_per_page must also be specified. When both are given, the data is broken up into pages with lines_per_page lines on each. The page returned is specified by page. -------------------------------------------------------------------- list_alias domain Rights required: SA_ADMIN, or QA_ADMIN. QA_ADMIN can only manage their own domain. Action: List all aliases for a domain. Currently, this scans the directory for aliases. It needs to be changed to use the new valias calls Tom just added. List all Mailbox accounts for a domain. -------------------------------------------------------------------- list_lists domain Rights required: SA_ADMIN, or QA_ADMIN. QA_ADMIN can only manage their own domain. Action: Send a list of all mailing lists within a domain. One entry per line, with a line containing only a '.' at the end. -------------------------------------------------------------------- get_ip_map ip_address Rights required: Anyone Action: Return the domain associated with this IP Address, if any. -------------------------------------------------------------------- add_ip_map ip_address domain Rights required: SA_ADMIN Action: Make an IP address point to a domain. WARNING: It does not look like there is any duplicate checking on this, so make sure what you enter is valid! I think I once got the IP and name backwards, and it was stored that way. The error checking belongs in the vpopmail library. -------------------------------------------------------------------- del_ip_map ip_address domain Rights required: SA_ADMIN Action: Delete an association between an IP address and a domain name. -------------------------------------------------------------------- show_ip_map Rights required: SA_ADMIN Action: Display the mapping between IP addresses and domain names. -------------------------------------------------------------------- get_limits domain Rights required: Any. SA_ADMIN can read all domains, all other users can only read their own domain. Action: Return Limits information for a domain. If no special limits are set, it returns the default limit settings for all domains. Find out where these files are kept, and add it here. max_popaccounts max_aliases max_forwards max_autoresponders max_mailinglists maxmailinglists disk_quota max_msgcount default_quota default_maxmsgcount disable_pop disable_imap disable_dialup disable_password_changing disable_webmail disable_external_relay disable_smtp disable_spamassassin delete_spam perm_account perm_alias perm_forward perm_autoresponder perm_maillist perm_quota perm_defaultquota -------------------------------------------------------------------- set_limits domain Rights required: SA_ADMIN, or QA_ADMIN with override_domain_limits rights. Action: Set Limits informaiton for a domain. max_popaccounts max_aliases max_forwards max_autoresponders max_mailinglists maxmailinglists disk_quota max_msgcount default_quota default_maxmsgcount disable_pop disable_imap disable_dialup disable_password_changing disable_webmail disable_external_relay disable_smtp disable_spamassassin delete_spam perm_account perm_alias perm_forward perm_autoresponder perm_maillist perm_quota perm_defaultquota -------------------------------------------------------------------- del_limits domain Rights required: SA_ADMIN Action: Delete the limits file for a domain. This will make the domain revert to the global limits set somewhere. (Find out where, and add it here.) -------------------------------------------------------------------- get_lastauth user@domain.ext Rights required: Any. SA_ADMIN can list any user, QA_ADMIN can list any user in their domain, USER can list only their own. Action: Return the last time and IP address from the last time the user logged in. -------------------------------------------------------------------- get_lastauthip -- D E L E T E D ! Merged with get_lastauth, use it instead. -------------------------------------------------------------------- add_list Rights required: SA_ADMIN, or QA_ADMIN. QA_ADMIN can only work in its home domain. Action: Add an ezmlm mailing list. Not implemented yet. -------------------------------------------------------------------- del_list Rights required: SA_ADMIN, or QA_ADMIN. QA_ADMIN can only work in its home domain. Action: Delete an ezmlm mailing list. Not implemented yet. -------------------------------------------------------------------- mod_list Rights required: SA_ADMIN, or QA_ADMIN. QA_ADMIN can only work in its home domain. Action: Modify an ezmlm mailing list. Not implemented yet. -------------------------------------------------------------------- quit, exit, q Rights required: Any Action: Shutdown the daemon. You should always call this before exiting the program communicating with the daemon. -------------------------------------------------------------------- help Rights required: Any Action: Display a list of the commands currently available to the client. The list will adjust itself to match the access rights of the userid with which the client is logged in. If the client is not logged in yet, only the "login", "clogin", "slogin", "help", and "quit" commands are shown. -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- 3 : R u n n i n g v p o p m a i l d For a simple quick test, just run the daemon at the command line. As root... # ./vpopmaild To run under tcpserver temporarily from the command line: As root... # tcpserver -vHRD 0 89 ./vpopmaild Running vpopmaild under daemontools is the only way to run it as a mission critical service. There is one important difference between this script and a "generic" script which usually sets up a service listening on IP address "0", or listening on every interface on the server. This is a MAJOR security hole- allowing clients to connect across the network allows somebody with a packet sniffer to watch every byte which goes across the wire- including passwords. This script sets up a service which only listens on 127.0.0.1, which on most systems is the "localhost" interface- which means that the packets never physically leave the machine, and therefore cannot be "sniffed" by other machines. Setting up the service Note that the commands below assume that your daemontools services are physically running in the /var/service directory. If you keep your services somewhere else, or want to set up your own service directory somewhere, that works as well- just make sure that the physical location is not under /service or you will not be able to reliably stop the service when needed. As root... # mkdir -m 1755 /var/service/vpopmaild # cd /var/service/vpopmaild Copy the following lines into a file named run in the directory you just created. Don't include the --- lines in the file, they just show the beginning and end of the file. --------------------------------------------------------------------- #!/bin/sh exec 2>&1 exec env - PATH="/usr/bin:/bin:/usr/local/bin" \ tcpserver -vHRD 127.0.0.1 89 ~vpoppmail/bin/vpopmaild --------------------------------------------------------------------- # chmod 755 run # mkdir -m 755 log # cd log Copy the following lines into a file named run in the directory you just created. --------------------------------------------------------------------- #!/bin/sh VQ="/var/qmail" exec env - PATH="$VQ/bin:/usr/local/bin:/usr/bin:/bin" \ multilog t n1024 s1048576 ./mail \ '-*' '+*ver: status:*' =lstatus --------------------------------------------------------------------- # chmod 755 run # ln -s /var/service/vpopmaild /service/ Wait a few seconds... # svstat /service/vpopmaild /service/vpopmaild: up (pid 22457) 7 seconds /service/vpopmaild/log: up (pid 22460) 7 seconds Using the service Once the service is running, you can test it by telnetting to localhost port 89. Go back to the section on Running the deamon for an example session. -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- 4 : B i t m a p d e f i n i t i o n This appeared early in the discussion leading to the daemon, so until I find a better place for it, I'll add it here. The important thing is the comments on what each bit is supposed to mean. This may get re-worked into documentation on the daemon. List of bits in the gid or flags field for a user, from a message from Ken on the vpopmail list. I'll try to give a detailed listing. #define NO_PASSWD_CHNG 0x01 If set, the code should not allow the password to be changed #define NO_POP 0x02 If set, reject pop authentications #define NO_WEBMAIL 0x04 If set, reject webmail authentications #define NO_IMAP 0x08 If set, reject imap authentications #define BOUNCE_MAIL 0x10 If set, bounce any incoming mail back to the sender #define NO_RELAY 0x20 If set, do not allow the account to relay email. This is useful for sites that want to have email accounts that are only allowed to send email internally. #define NO_DIALUP 0x40 If set, code should not allow dialup access. This was originally added to support radius sites. #define V_USER0 0x080 #define V_USER1 0x100 #define V_USER2 0x200 #define V_USER3 0x400 After adding the NO_DIALUP flag we realized there may be other flags people will want that are not directly used by any email code. #define NO_SMTP 0x800 If set, do not allow smtp connections. #define QA_ADMIN 0x1000 If set, the user is granted admin privileges in qmailadmin #define V_OVERRIDE 0x2000 If set, the user is not subject to domain limits. Part of the vlimit code. #define NO_SPAMASSASSIN 0x4000 If set, (and --enable-spamassassin=y) do not process the incoming mail through spamassassin. #define DELETE_SPAM 0x8000 with --enable-spamasssassin=y setting this flag will delete all email above the users required_hits preference. ============================================================================== The original readme from Ken: To run as daemon: tcpserver -vHRD 0 89 ./vpopmaild Then as client telnet localhost 89 Or to run on the command line for testing ./vpopmaild First login. example: login postmaster@example.com password Then for list of commands: help -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- -------------------------------------------------------------------- 5 : E r r o r M e s s a g e F o r m a t Error messages are in the form ERR- major.minor message Major is the error code that identifies what kind of error has been encountered, and determines which message is displayed. Minor is a number that identifies which test within the source code triggered the error message. The last two digits should indicate the error number within a function, and the rest should identify which function the failure happened in. You can search the source code with this value to find the point where an error happened. The actual error messages are stored in the file vpopmaild.msg for easy translation. Once there are other language files, I'll create a directory to store the various language files, and use a symlink to select a language. Error messages are set at comile time. 0.X represents a message passed up from fpopmaild primitives, and does not otherwise follow the standard error reporting structure. (yet?)