Download PDF Version of this Document
August 20, 1996
80-8359-1 Revision X1
QUALCOMM Inc.
Laurence Lundblade
For more information write to <emsapi-info@QUALCOMM.com>
6455 Lusk Blvd.
San Diego, CA 92121-2779
USA
Copyright (c) 1995, 1996 QUALCOMM Incorporated.
All rights reserved. Printed in the United States of America.
Note: sections one through five of this document provide overview, background and implementation guidelines for the EMS API. Detailed reference information for implementation begins in section six.
The Eudora Extended Message Services API (EMS API) is designed so that third party plug-ins can be added to Eudora by the end user. Plug-ins may be supplied by Qualcomm, an independent vendor, be available as shareware, or be authored by the end user. Plug-ins may perform transformations on e-mail messages as they are received, as they are sent or on the command of the user. The API is general enough to accommodate transformations ranging from compression/decompression, to file format conversions, graphic format conversions, human language translation, digital signing and others. U.S. developers of plug-ins which perform encryption/decryption should contact the U.S. Department of State's Office of Defense Trade Controls in order to determine the licensing requirements applicable to exports of such translator plug-ins from the United States.
When Eudora starts up it will search for plug-ins on the user's system. It will look for Windows DLL's or Macintosh Components in a set of specific places on the user's system. Once located, the plug-ins will show up as menu items and check boxes in the Eudora user interface and/or be invoked automatically as messages are sent and received. When invoked, plug-ins may interact directly with the user by putting up their own dialogue boxes and user interfaces objects.
Each plug-in may have several translators in it. A translator performs some transformation on a message. It is often convenient to put several translators in one plug-in because they may share a lot of code or other resources. It is also possible for a translator to be used simply as a hook for access to messages as they are received, viewed or sent. That is, a translator may perform no translation at all.
The translators in a plug-in are executed in the following contexts:
On-arrival -- When the message arrives from the mail server non-interactive translations can occur. It is also possible for a translator to indicate processing (MIME parsing and further translation) of the message structure should be suspended until it can be done in an interactive context.
On-display -- When the message is selected for display an interactive translator may be automatically run. The result will be displayed to the user.
On-request -- Translations for both received messages and messages under composition can be selected from a menu item. The translation will be performed right away and the result shown to the user.
Q4-transmission -- More properly described as "queue and call on transmission," this translation is selected by icon from the top bar of the message composition window. Then when the message is actually being transmitted to the SMTP server the translation is performed.
When a plug-in is loaded, it registers in which of the above contexts each of its translators wishes to be called in. For example a plug-in which does digital signing may have two translators in it, one to add a signature to an outgoing message, and one to verify a signature on an incoming message. The translator which adds the signature may register to be queued and called on transmission, and the signature verification translator may register to be called on-display.
The EMS API makes heavy use of the MIME standard for describing and representing the data type of an e-mail message and its sub-parts. The design of the API and the SDK is intended to make it possible to implement plug-ins without an in-depth understanding of MIME and without having to implement large parts of the MIME standard in the plug-ins.
Translators may operate on the whole message or only on any sub-part of the message. Eudora performs a full traversal of the MIME structure of the message and calls translators on parts and sub-parts as they wish to be called. This will allow plug-ins to work on individual parts of a multipart message without having to implement any MIME parsing.
The data type of a translator's input and output data is labeled using MIME. For example, the MIME typing might include the text format and character set, the type of compression, or the type of graphic image (e.g., GIF or JPEG).
Translators can create and access their own data files or make use of such files created by other applications. They may also access and modify data that is shared with a companion application.
Most individual translations that are a candidate for implementation via the EMS API come in pairs or groups. Examples are compression and decompression, Spanish to English and English to Spanish, digital signing and authenticating, and certificate management. An implementation of a group usually will have a lot of code in common and is most easily installed and configured by the user as a single entity. Thus, plug-ins are implemented as a collection of translators.

Each plug-in has a set of entry points or functions that are called by Eudora:
ems_plugin_version Is called first to get the API version number the plug-in uses and thereby the calling conventions for the other functions.
ems_plugin_init Is always called second and only once as the plug-in is loaded during Eudora startup.
ems_translator_info Supplies basic info about individual translators. Is called once for each translator on start up and at other times when specific items (like the icon) are needed for an individual translator.
ems_can_translate_file Called to check whether a translation can be performed on a particular item, before the actual translation is attempted.
ems_can_translate_buf As above, but works on a buffer instead of a file (not in API version 1).
ems_translate_file Called to actually perform the translation.
ems_translate_buf As above, but works on buffers instead of a file (not in API version 1).
ems_plugin_finish Called when Eudora exits.
ems_free (Windows only) Called by Eudora to free data structures passed from the plug-in to Eudora.
Some of these functions are optional, but every translator must supply a minimal set of these functions. The minimal set includes ems_plugin_version, ems_plugin_init, ems_translator_info, ems_plugin_finish and either the pair ems_can_translate_file and ems_translate_file or ems_can_translate_buf and ems_translate_buf. Except ems_plugin_init and ems_plugin_finish, all of these functions take an argument which specifies which of the translators in the plug-in is being called. For example, if a plug-in was loaded that performs compression/decompression and Eudora wanted to call the data compression translator, it would call ems_translate_file with the ID of the compression translator. If it wanted to perform decompression it would also call ems_translate_file, but it would pass the ID of the decompression translator instead.
For Windows, a plug-in is implemented as a DLL. The above entry points are implemented as a set of functions in the DLL. A standard C calling convention is used, and the DLL is located by searching a specific set of directories (see section 6). The actual implementation may be in C, C++ or other, as long as the standard C calling convention is followed.
On the Macintosh, the EMS API makes use of the Component Manager to load and link the plug-in into Eudora. The calling convention thus conforms with what the Component Manager specifies. It is basically the stack-based Pascal calling convention. The details involved in implementing this can be skimmed over by using glue code supplied in the SDK. Plug-ins can be written in any language as long as the calling convention is adhered to. Plug-ins may also be implemented from code fragments or shared libraries with some small amount of glue code. Exact details of what is needed to build a component are given in section six.
On the Macintosh it is also possible to statically link a plug-in with a test driver, the source for which is included in the SDK. It may be easier to debug plug-ins with the test driver since some of the Macintosh tools don't work as well on components.
Each plug-in must have a distinct ID number. To ensure these ID numbers are unique they are allocated by Qualcomm. To obtain a unique ID, send a blank message to <emsapi-ids@qualcomm.com>. A list of several IDs will be returned by an auto-responder. The auto-responder doesn't actually track IDs by individuals or organization, it just returns monotonically increasing integers, so it's OK to request a second or third set if needed.
Plug-ins may permanently store configuration and other information as needed. Eudora provides no mechanism for this, but does suggest the name of a directory so plug-in configuration can track Eudora settings for users with multiple settings files. Basically, plug-ins should store state like any other application using a Preferences file or a .INI file. Shared configurations can be dealt with on a case-by-case basis depending on what is appropriate for the plug-in.
Plug-ins may also freely access other data and files and may share data with other applications. An example of this might be a set of dictionaries for language translation. Translators may also make accesses across the network. An example of this might be to access to directory service to get certificates.
There are version numbers for three things related to the EMS API. As Eudora changes it will have different version numbers. However every version of Eudora will not result in a change in the API definition so the API has its own version number. It is a single integer. It is also possible that Eudora will support multiple API versions for backward compatibility. The third version number is associated with the SDK. It may change independent of the Eudora version number. Both the Eudora version and the SDK version will change when the API version number changes. The current status is:
API: Current version is 2
Eudora: Macintosh versions 3.0 and higher support only API version 1
Windows versions 3.0b11 and higher support API version 2
SDK: Current Macintosh version is 1.0b3 and supports only API version 1
The current Windows version is 1.0b2 and supports API version 2
This document mentions in italics a number of features that are not part of version 2 of the API. These are usually items that require Eudora store messages internally in MIME format, which it doesn't do now. This change is planned. Because of this some of the API described here is not supported.
This section discusses the scheme used to describe the types and data formats of the input and output data that is actually translated. Most of the discussion centers on MIME, the Internet standard for encoding, structuring and typing data in Internet email.
Before delving into MIME related issues it is useful to mention that translators may operate on data in either files or buffers. A translator may be designed to accept its input data and generates its output data in files, in which case file names will be passed across the API. A translator may also accept and generate its data in buffers. Eudora will supply data in either format depending on the presence of the file-based or buffer-based translate function in the plug-in. The choice is up to the implementor. Often file-based translations are easier to write, but buffer-based translations are usually more efficient. Version 1 of the API does not support buffer-based translations, though it is expected to be available in version 3.
The rest of the section is related to MIME. The EMS API uses MIME in two ways. The first use of MIME is used to describe the type of the input and output data for a translator. All objects that are operated on via the EMS API have a MIME type. A translator usually determines what messages and message entities to operate on by the MIME. A translator must always specify the MIME type of its output when it returns the result to Eudora. These MIME types are passed to and from Eudora as parameters in the API entry point functions. Examples of types are text/plain for plain text, image/gif for a GIF image, and multipart/signed for an RFC-1847-style signed message.
The second use of MIME is for the format of the actual data. This is the data that is passed across the API by referencing a file name, or by a sequence of calls on buffers. The translated data can be in one of two basic formats, the native local format (e.g., plain text in the Macintosh character set or an unencoded GIF image), or in full MIME format (e.g., with MIME headers, canonicalization, and transfer encoding). It is expected that most translators need only operate on data in the local format, and thus do not need to do any MIME processing assigning and checking the MIME types as described above.
Plug-ins that operate on multipart MIME entities are the ones that will need to have their input and output data in MIME format. That is, the API uses standard MIME format to represent multipart MIME entities. One example of a plug-in that will require MIME format data is one that implements RFC-1847-style signed messages, since that format uses a two-part entity. One part is the signed data, and a second part is the signature. Another example is a plug-in that wishes to compress (or otherwise process) the full outgoing message including attachments. It can request full MIME structure of the outgoing message, process it as it wishes, and send it out in another format.
A plug-in selects whether it uses MIME format on input and output by setting flags in the description information returned to Eudora.
As mentioned above, each entity operated on by plug-ins is described by a MIME type, and this type is passed across the API in parameters to the entry point functions. (The term entity is used to refer to a message or a sub-part of a MIME message) The types are used by the translators to determine whether they should run on some data or not.
The EMS API defines a C data structure for passing MIME type information across the API to describe the data object being operated on. Source code for managing the data structure is available in the SDK.
When performing a translation, the plug-in will check the MIME type of the input data. This is usually the main criteria for the translator to decide whether or not it will perform the translation. The type is passed in by Eudora, so the translator doesn't actually have to examine the data to be translated. When the translation is complete, the translator must return the MIME type of the result to Eudora. Except for translators invoked in the on-request context, the MIME types for the input and output must be different (even if just by a MIME parameter) to avoid circular translations.
This document has referred to the term MIME entity. This term comes from the MIME standard. In the simplest case a MIME entity is just an email message. The MIME standard assumes that a message with no MIME headers at all is a simple MIME entity of type text/plain with no transfer encoding or other MIME features. A multipart MIME message is also considered a MIME entity, as are each of its sub-parts. If a message has nested multiparts, then each multipart is also a MIME entity. Basically a nested multipart MIME message can be viewed as having a tree structure, and every node in the tree (leaf or branch) is considered a MIME entity.
Plug-ins have the ability in certain contexts to translate any MIME entity in the structure of the message into a completely different MIME entity. A leaf node could be translated so that it is a multi-level, nested multipart entity. A message that has deeply nested MIME structure can be translated into a single text part.
It is expected that most translations will work on simple leaf MIME entities, those that do not have a top level type of multipart. In certain contexts, Eudora performs the traversal of the nested MIME structure and makes the data in the leaves available for translation so the plug-in author doesn't have to perform the traversal.
As is described in more detail later, each translator may be offered each MIME entity in the MIME structure to translate. It usually decides based on the MIME type whether or not it wishes to translate the entity. If the entity being translated is a multipart entity, then the data must be in MIME format. If it decides to translate the entity, the data is delivered in one of two formats as described in the next section.
As mentioned earlier, data for a translator can be in one of two formats, one of which is the local or native non-MIME format. The local format is just the plain data as it normally is for the particular platform. Examples are Macintosh text (in Macintosh character set with CR line endings), DOS text, a JPEG file, or a Word document. Data in MIME format has additional headers and encoding as described below.
Translators that wish to use the local format should not set the EMSF_REQUIRES_MIME flag. At present only the on-request context supports data in the local format.
The actual format for each MIME entity is described by the standard or description for that MIME type (e.g., an image/gif entity will be described by the MIME standard for that type, which most likely references the standard for GIF images). Text formats however pose an unusual problem because they vary significantly between the Macintosh, Windows, etc. and there are no MIME documents describing local text formats. To solve this problem the translation API defines a type tag for the local text format for each platform.
On the Macintosh, the MIME type for text in the local format is application/x-mac-text. Application/x-mac-text has CR as the end of line and is in the Macintosh character set. The MIME type returned by an on-request text translator should be the same application/x-mac-text.
For Windows, text in the local format is of type text/plain, is in the ISO-8859-1 character set and has lines ending in CRLF. Similarly, the text returned by a translator should be in the same format and the MIME type should be text/plain.
At present, enriched text is removed before translation in the on-request context, but not other contexts.
The above is perhaps a complicated way of saying that on the Macintosh a simple text translator should accept and generate data of type application/x-mac-text and it can operate on data in standard Macintosh formats. Similarly for Windows it should accept and generate data of type text/plain.
MIME formatted data for translation is available in all the translation contexts. The on-request context is limited to text data types. When a translator requires canonical MIME (sets the EMSR_REQUIRES_MIME flag), Eudora supplies the data as follows:
* Converts the base data objects to their canonical format as defined by its MIME type and subtype. The most common canonicalization is to convert text so the line endings are CRLF and the character set to a standard one like ISO-8859-1.
* It applies content transfer encoding so the result is 7-bit clean limited line length data. This is done using Eudora's usual algorithm for determining which transfer encoding is best. Eudora uses quoted-printable transfer encoding for text data and base-64 for non-text data. Whether the data is text or not is determined by the MIME type mapping settings in Eudora.
* It assembles the MIME entity with the appropriate MIME headers. These consist of the MIME-Version, Content-type, and Content-transfer-encoding headers with appropriate parameters, message part boundaries, etc.
Translators that return full MIME should return similar entities. The MIME-version header should alwyas be included with one exception. The MIME version header should not be output by a translator for translations on outgoing messages on the Macintosh. Macintosh Eudora always assumes MIME version 1 and generates the header for its outgoing messages. If the Content-type is omitted text/plain will be assumed, and if the Content-transfer-encoding is omitted, 7bit will be assumed. Note that the entities Eudora supplies will always be encoded for 7bit transport, however the translator can return the entity with any standard transfer encoding as long as it is tagged correctly. Other MIME-related Content-* headers can be included. (For version 1 of the API binary encoding is not allowed. That is, if a translation results in a binary object, the translator should transfer encode it with something like base64 before passing it back to Eudora).
Below is an example of text in the MIME format. The lines would end with CRLF and the data would be in this format no matter if the translation is being done on the Macintosh or Windows. If it were not in MIME format it would not have the extra header, nor the quoted printable transfer encoding, and the character set might not be ISO-8859-1.
Content-type: text/plain; charset=iso-8859-1 Content-transfer-encoding: quoted-printable This is the message text and this =e1 is an a with an accent.The API uses the tag text/plain for the local format for Windows because the character set and end of line character are the same as the Internet standard. The above entity in Windows local format would be as follows and has no header or transfer encoding.
This is the message text and this is á an a with an accent.
Plug-ins and translators are displayed in the user interface in several places. On the Mac all plug-ins are shown in the About Extended Message Services dialog box found under the apple menu. On Windows the About Plug-ins dialog is accessible under the Help menu.
Translators that can operate in the on-request context are displayed as menu items. They are displayed for both received messages and messages under composition. When invoked they are performed immediately on the displayed message. These menu items only work when there is a message displayed, and should not be used a general hook for adding menus to Eudora.
Translations that can be performed on outgoing message are displayed as check boxes in the button bar of the message composition window. While the user is composing the message, they may be selected. When the user completes composition by hitting the send/queue button, the translation may be performed if it operates in the on-completion context. If it operates in the on-transmission context, it is not performed until the message is being transmitted. For version 1, only the on-transmission context is supported.
The translators may return a status icon and text message. If these are returned in the on-display or the on-request contexts, they will be displayed as part of the message with a side-bar indicating which part of the message they apply to.
Some translators operate without any display in the user interface. These are translators that work in the on-arrival context. They process messages as they are down-loaded from the mail server.
A translator supplies two functions that are used in the translation process itself, ems_can_translate_file and ems_translate_file. There are also versions of these functions that operate on buffers instead of files. A translator may have functions only for the file operation, only for the buffer operation, or both. Version 1 only uses file-based operations.
Translations may be performed in different contexts. These contexts are different events that happen to a message, such as its arrival, display, or transmission. The details for each are described below. A given translator can work in any number of these contexts. When a translator is called by Eudora the context it is being called in is specified by a parameter so it may behave differently in different contexts.
When Eudora processes a message for translation the function ems_can_translate_file is called for each potentially translatable MIME entity before actual translation is attempted. In some cases this is for the sake of efficiency since ems_can_translate_file is more efficient than the full translation function. The function ems_can_translate_file also has a special return code, namely EMSR_NOT_NOW, to delay further processing of a message to a later time. The main purpose of EMSR_NOT_NOW is for a translator to delay all further MIME parsing and translation. This may occur because the translator works on unparsed MIME entities. It may also wish to preempt translation in a non-interactive context so the translation cab be performed later in a context where interaction with the user is allowed.
The function ems_translate_file actually performs the translation. It is passed a large number of parameters, including the input MIME type, the location of the data to translate, the address of a progress reporting function, and the e-mail addresses on the message. Exact details are given in Section six.
The on-arrival context processes messages as they are down-loaded to Eudora from the mail server. That is, when Eudora is talking to the POP server. In general, translators in this context should not interact with the user or cause long delays (more than a few seconds) or they will disrupt the POP protocol session with the mail server. This context is useful for automatically processing incoming messages. It is also necessary to use this context so that translations can be performed in the on-display context. This will not be necessary in a future version when Eudora switches to internal MIME storage.
The actual algorithm used by Eudora to call translators is integrated with Eudora's MIME parsing. It involves a pre-order traversal of the MIME structure of the message (intermediate nodes are processed before the leaves). As each MIME entity is visited the ems_can_translate_file function of each translator is called on it. If it returns EMSR_CANT_TRANS, the next translator is tried. The list of translators that are tried are the ones that indicate they work in the on-arrival context and are ordered by type as listed below. If ems_can_translate_file returns EMSR_NOW, the translation is immediately performed and the output of the translator replaces the MIME entity that was translated. After a translation is made, the entire process of checking each translator in the list at each node in the pre-order traversal is started over for that MIME entity. When a complete pass is made through all translators for an entity without performing any translation, the MIME parse of the entity is made and its sub-parts are processed. Since most messages are not multipart and most will not be translated, this usually amounts to a single pass through the potential translators.
If the ems_can_translate_file function returns EMSR_NOT_NOW, then all parsing stops and the MIME entity as it stands is written out for later processing. The entity is written to a file and a link to the file is placed in the original message. When the user clicks on the link, the translation process is resumed. This will be changed in a future version when Eudora supports MIME storage. It may not be required that the user click on an icon.
In general, the order of the translations in the on-arrival context is driven by the MIME types in the received message. When there are ambiguities, the order is by type as follows:
EMST_CERT_MANAGEMENT EMST_PREPROCESS EMST_SIGNATURE EMST_COALESCED EMST_COMPRESSION EMST_GRAPHIC_FORMAT EMST_TEXT_FORMAT EMST_LANGUAGETranslations in the on-arrival context should not interact with the user. If they need to interact with the user they should delay processing until the on-display context by returning EMSR_NOT_NOW. A translator may also vary the function it performs based on the context in which it is called. For example a signature verification translator called in the on-arrival context may find it useful to fail silently if it does not have the certificate needed for verification rather than interrupt the message down-load to prompt for a certificate.
Translators in this context must accept MIME and generate MIME. That is, they must set the EMSF_REQUIRES_MIME and EMSR_GENERATES_MIME flags. Thus these translators must be prepared to remove content transfer encoding, and parse and generate basic MIME structure. It is likely that this restriction will be removed in a future version.
Translations in the on-display context are performed when a user clicks on a translator icon that appears in a message body. The translator icon is put in the message body as a result of the ems_can_translate_xxx function called in the on-arrival context returning EMSR_NOT_NOW. When the user clicks on the icon, the parsing, recursion and translation on the MIME structure that was begun in the on-arrival context is resumed. When the traversal is complete the resulting MIME entity is displayed to the user, in the message window. This includes icons for attachments that were part of the original message or attachments that were generated as part of the translation process. Attachments can also be removed as part of the translation process.
Important differences between this context and the on-arrival context are that ems_can_translate_xxx must never return EMSR_NOT_NOW and that translations may interact with the user. The on-display context has the same restriction as the on-arrival context that the input and the output must be MIME format.
When Eudora messages are stored in MIME format, translations in this context may be performed automatically when the message is displayed - that is when the user clicks on the message index to display a particular message. There will be no need for the user to click on a translator icon in the message body.
On-request translations are those that are performed on the currently displayed message. Translations in this context are usually the simplest to create.
Translators that work in this context are displayed in a menu item in a sub-menu of the Edit menu. When the user selects one, the translation is performed on the current message whether it is a received message or a message under composition. If a section of the message is selected, then only the selection is processed. When complete, the translated data replaces the original data and the message is marked as changed. Translations in this context may be fully interactive. If there is no open current message, the menu items for these translations are.
Since Eudora supports only translation of text items in this context, translators that cannot operate on text are not placed in the menu at all. Eudora determines this by ems_can_translate_file on the MIME type text/plain. On the Macintosh it also calls it on application/x-mac-text. If the result is EMSR_NOW to any of these types, the translator will be placed in the menu.
On-request translators may set the EMSR_REQUIRES_MIME and EMSR_GENERATES_MIME flags or not. If the flag is set the data type will be text/plain and the line endings will be CRLF and it should return the same. On the Macintosh the local format (described in section 3.3) will be used if the flags are not set. If a translation is attempted on text/enriched, the rich formatting will be removed before translation. This is not the case for other translation contexts.
Translators that work in this context are displayed in the top bar of the composition windows and may be selected by the user. They are toggled turned on and off by clicking a button with the translator's icon on it (Macintosh) or by selecting the translation from a drop-down menu (Windows). The translation is actually performed later when the message is being transmitted to the mail server via SMTP. If a message under composition is saved and resumed later, the toggled state of all translators working in the Q4-transmission context will be retained.
Translation in this context must operate on the full MIME structure and must work on the whole message (must set EMSF_GENERATES_MIME, EMSF_REQUIRES_MIME and EMSF_WHOLE_MESSAGE). Translations are performed in the reverse of the order listed above for on-arrival translations. This ordering does prevent certain useful chains of translations from being performed (e.g., first a language translation, then a text format translation), but this disadvantage is out weighed by it being simpler to implement, and simpler for the user.
A future API version may relax these restrictions and provide a full depth-first traversal of the MIME structure. The EMSF_WHOLE_MESSAGE flag indicates the translator wishes to operate on the whole message, thus it will not be offered the intermediate nodes for translation. This is only of interest for translators that function on multipart MIME entities.
The ems_can_translate_xxx function for this context is called after the user clicks the Send/Queue button. This allows the translator to perform a quick check that the translation will be possible later when the message is transmitted. If ems_can_translate_xxx returns EMSR_CANT_TRANS and an error string, the string will be displayed to the user, and the message will not be sent or queued. The user has the option of toggling the translation off or adjusting the condition that caused the translation for fail.
It is possible for the user to queue an incompatible set of translations (e.g., the MIME type output by one translation is not acceptable input to the next).When this happens the user will receive an error and can then go back and deselect translations.
Translations in this context may be fully interactive. A future version of the API may require that translations in this context not be interactive because delays due to interactivity can disrupt the SMTP connection. This restriction will not be made until the on-completion context is functioning.
This context will not be supported until Eudora stores messages in MIME format.
Translators that set this option have their icon displayed in the top bar of the composition windows and may be selected by the user. Then when the user clicks the Send/Queue button the translation is performed. They will be performed in the reverse of the order listed in the section above describing on-arrival translations and they will be performed with a depth-first traversal of the MIME structure rather than a pre-order traversal. The output of the translator always replaces the original part.
Note that it is possible for the user to queue an incompatible set of translations. The output of one translator may not be suitable as input for the next. In this case translation will fail with an error message when the user clicks the Send/Queue option. This is actually not a very serious concern because it is anticipated that there are few translators for this context that would interact in this way.
Translations in this context may be fully interactive. Translators must also supply an icon suite or they will not be displayed.
Note that if a particular translator says it can work this and the Q4-transmission context it will always be called on completion and never on transmission.
For API version 3, an address book context (EMSF_ADDRESSBOOK) will be added. While this is not actually a translation on a message, it will allow plug-ins a hook in the address book. Translators that register to be called from the address book will have an icon and description shown in the address book. When the icon is clicked on, ems_translate will be called with the main nick-name, the main name and the addresses for the entry. The data and the MIME type will be empty.
This section describes in full detail the calling interface, constants and related data structures. These definitions are the same as found in the include emsapi-mac.h and ems-win.h. The basic data items and their semantics for the API do not vary between the Macintosh and Windows platforms, but the function declarations and data formats do vary. Having this variance between platforms makes the API simpler and less abstract for each platform, and also increases its efficiency. In the following sections both the Macintosh and Windows declarations are shown.
For both the Mac and Windows platforms, header files, skeleton source code, and samples are part of the SDK. In particular, this should help with some of the complexity in working with the Macintosh Component manager. The author should be able to create a plug-in by creating the necessary C functions and some associated resources.
The first three letters, EMS, identify EMS API-related constants. The third letter groups related constants. All constants should be stored as a long (32 bits). The constants are identical on all platforms.
Translator return codes report the general success or failure of a translation and are not intended to express all possible results of a translation. Usually more specific results are given via error messages that are displayed to the user by Eudora.
/* ----- Translator return codes --- store as a long --------------------- */
#define EMSR_OK (0L) /* The translation operation succeeded /
#define EMSR_UNKNOWN_FAIL (1L) /* Failed for unspecified reason */
#define EMSR_CANT_TRANS (2L) /* Don't know how to translate this */
#define EMSR_INVALID_TRANS (3L) /* The translator ID given was invalid /
#define EMSR_NO_ENTRY (4L) /* The value requested doesn't exist */
#define EMSR_NO_INPUT_FILE (5L) /* Couldn't find input file */
#define EMSR_CANT_CREATE (6L) /* Couldn't create the output file */
#define EMSR_TRANS_FAILED (7L) /* The translation failed. */
#define EMSR_INVALID (8L) /* Invalid argument(s) given */
#define EMSR_NOT_NOW (9L) /* Translation can be done not in current
context */
#define EMSR_NOW (10L) /* Indicates translation can be performed
right away */
#define EMSR_ABORTED (11L) /* Translation was aborted by user */
Every
translator must be one of the following types. The type is used to determine
the ordering of translations in certain contexts when ambiguities arise (see
the previous section on The Translation Process). When, in a particular
plug-in, translators of type EMST_SIGNATURE and
EMST_PREPROCESS are selected together in the
EMSF_Q4_TRANSMISSION (and in version 3, the
EMSF_Q4_COMPLETION) context, and a translator of type
EMST_COALESCED is available it will be called instead of the two
translators. Translators of type EMST_COALESCED should not supply an
icon if it is desired that they not be displayed and selectable on the
composition window. Basically the translation types are used for ordering and
grouping the translations and for nothing else.
/* ----- Translator types --- store as a long ---------------------------- */ #define EMST_NO_TYPE (-1L) #define EMST_LANGUAGE (0x10L) #define EMST_TEXT_FORMAT (0x20L) #define EMST_GRAPHIC_FORMAT (0x30L) #define EMST_COMPRESSION (0x40L) #define EMST_COALESCED (0x50L) #define EMST_SIGNATURE (0x60L) #define EMST_PREPROCESS (0x70L) #define EMST_CERT_MANAGEMENT (0x80L)The following flags specify critical information about a translator. They specify which context it may operate in, whether or not it can be called on the whole message or not, and the format of the input and output data. Eudora uses these flags to decide when to call the translator, and how to format and process the input and output data from the translator.
/* ----- Translator info flags and contexts --- store as a long ---------- */
/* Used both as bit flags and as constants */
#define EMSF_ON_ARRIVAL (0x0001L) /* Call on message arrivial */
#define EMSF_ON_DISPLAY (0x0002L) /* Call when user views message */
#define EMSF_ON_REQUEST (0x0004L) /* Call when selected from menu */
#define EMSF_Q4_COMPLETION (0x0008L) /* Queue and call on complete
composition of a message (API v2 only) */
#define EMSF_Q4_TRANSMISSION (0x0010L) /* Queue and call on transmission
of a message */
#define EMSF_WHOLE_MESSAGE (0x0200L) /* Works on the whole message even if
it has sub-parts. (e.g. signature) */
#define EMSF_REQUIRES_MIME (0x0400L) /* Items presented for translation
should be MIME entities with
canonical end of line representation,
proper transfer encoding
and headers */
#define EMSF_GENERATES_MIME (0x0800L) /* Data produced will be MIME format */
/* all other flag bits in the long are RESERVED and may not be used */
API
version 3 will include a flag called EMSF_ALL_HEADERS. This
must be used with EMSF_REQUIRES_MIME,
EMSF_WHOLE_MESSAGE and EMSF_GENERATES_MIME.
When this flag is set all the headers of the message will be given to the
translator. The translator must then return the complete set of headers, though
it is free to modify them.The final following constants define the API version number, the component type used on the Macintosh, and the out_codes that should be returned from ems_translate_xxx when called on a translator of type EMST_SIGNATURE. The component type goes in the thng resource of the component.
/* ----- The version of the API defined by this include file ------------- */ #define EMS_VERSION (1) /* Used in plug-in init */ #define EMS_COMPONENT 'EuTL' /* Macintosh component type */ /* ----- Translator and translator type specific return codes ------------ */ #define EMSC_SIGOK (1L) /* A signature verification succeeded */ #define EMSC_SIGBAD (2L) /* A signature verification failed */ #define EMSC_SIGUNKNOWN (3L) /* Result of verification unknown */
/* typedef struct emsMIMEparamS **emsMIMEparamHandle; /*Mac style declaration */
typedef struct emsMIMEparamS **emsMIMEParamP;
typedef struct emsMIMEparamS {
Str63 name; /* MIME parameter name */
Handle value; /* handle size determines string length */
struct emsMIMEparamS **next; /* Handle for next param in list */
/* emsMIMEparamHandle next; /* Mac style declaration for above */
} emsMIMEparam;
/* typedef struct emsMIMEtypeS **emsMIMEtypeHandle; /* Mac style declaration */
typedef struct emsMIMEtypeS **emsMIMEtypeP;
typedef struct emsMIMEtypeS {
Str63 mime_version; /* MIME-Version: header */
Str63 mime_type; /* Top-level MIME type: text,message...*/
Str63 sub_type; /* sub-type */
emsMIMEparam **params; /* Handle to first parameter in list */
/* emsMIMEparamHandle params; /* Mac style declaration of above */
} emsMIMEtype;
On
the Macintosh, strings passed from a translator to Eudora (such as
descriptions, error messages and email addresses) are Pascal strings. Eudora
will pass a pointer to the location where the Handle to the string
should be returned. The translator must allocate this Handle with
NewHandle() so that Eudora can free it with
DisposeHandle().File path names are not used. Instead Eudora passes a pointer to an FSSpec on the stack. (Translators never return file names to Eudora).
For ems_can_translate_xxx and ems_translate_xxx (see the description of the calls further along), Eudora passes a block of e-mail addresses to the translator. The block is a Handle to an array of Handles. Each of the Handles in the array is a Handle to a Pascal string.
The structures representing a MIME type are also Handles allocated with NewHandle(). Limited-length Pascal strings are used for all components of the MIME type, except for parameter values. The parameter value is a Handle to a string the length of which is determined by the size of the Handle. The parameter value is not a Pascal string because its length can potentially exceed that of a Pascal string. It is also not NULL-terminated as the length comes from the handle size.
When Eudora passes a pointer to a location in which it expects data to be returned by a translator, it may pass NULL. Translators must check that the pointer to the location is not NULL before placing a value in it.
/* ----- Functions passed across the API --------------------------------- */
typedef short (FAR* emsProgress)(short); /* The progress function */
/* ----- MIME type data passed across the API ---------------------------- */
typedef struct emsMIMEparamS FAR*emsMIMEParamP;
typedef struct emsMIMEparamS {
char FAR* name; /* Mime parameter name (e.g., charset) */
char FAR* value; /* param value (e.g. us-ascii) */
struct emsMIMEparamS FAR* next; /* Linked list of parameters */
} emsMIMEparam;
typedef struct emsMIMEtypeS FAR*emsMIMEtypeP;
typedef struct emsMIMEtypeS {
char FAR* mime_version; /* The MIME-Version header */
char FAR* mime_type; /* Top-level MIME type */
char FAR* sub_type; /* MIME sub-type */
emsMIMEparam FAR* params; /* MIME parameter list */
} emsMIMEtype;
For
Windows, ASCII strings for descriptions, error messages, file names, addresses
and components of the MIME type structure are all NULL-terminated strings. They
may be allocated any way the plug-in author wishes and is referred to as the
plug-in's internal allocator. Eudora will call ems_free as supplied
by the plug-in to free the storage when it is finished with the data.The icons returned by ems_plugin_init for the whole plug-in should be a 32x32 HICON. The icons for the individual translators should be a 16x16 HICON (creating the 16x16 HICON may involve creating a HICON and deleting the 32x32 part). All the icons should be allocated with the plug-ins internal allocator so Eudora can free them by calling ems_free.
When Eudora passes a pointer to a location in which it expects data to be returned by a translator, it may pass NULL. Translators must check that the pointer is not NULL before placing a value in it.
As mentioned previously, plug-ins on the Macintosh are implemented as Components. Components are used, rather than other mechanisms such as Code Fragments, because they work on all Macintosh hardware from the 68000 to the PowerPC, and on MacOS system 7.0 through current versions. It is also expected they will be supported in future versions of MacOS. Though creating a component can be complicated, the SDK provides most of the needed glue source code, and the job should be easier.
In general the plug-in author needs to implement a minimal set of the entry point functions. When the Component is built the thng resource of the component must have type `euTL'. The version number specified in the thng resource must be a valid translation API version number. The upper 16 bits can be set to the value of the constant EMS_VERSION from the API include files. The sub-type resource is not used, but it must be unique or the translator will not be loaded by the Component Manager. There is currently no registry for sub-types to guarantee their being unique, but this not expected to be a problem. The author should make one up of their own. It must not be all lower case letters as those are reserved by Apple. Other fields of the component resource such as flags, icon, and descriptions are ignored.
The SDK includes two files for building a plug-in. The first, tlapi-mac.h, includes the constants and data structures listed here. It includes prototypes for the eight functions that are needed. For building the translator as a component, the file ems-component.c can be used as the component main. It includes the necessary component manager glue to accept the standard component manager calls as well as the API calls. When it receives the API calls, it sets up the calling stack frame and then calls the functions which are proto-typed in tlapi-mac.h. Thus ems-component.c should be compiled as a normal C file and linked into the component.
In order to compile ems-component.c, the template file usertrans.h must be modified for the plug-in being authored. A sample is included. It contains two sections. One is the definition of the structure tlUserGlobals. This is a structure that is passed as the first argument for all the API calls. The translator can define data it wants to be carried between calls to the API and store it here. This structure is automatically allocated and managed by the component manager glue in ems-component.c. Also in usertrans.h are C pre-processor definitions for eight constants that indicate whether an API call is implemented by the particular plug-in. Each constant should be defined to either true or false.
Eudora looks in a pre-defined set of directories for the Components that are EMS API plug-ins. This is done at start-up time. Each plug-in discovered is loaded and becomes active. The plug-ins must have a thng resource as described above or they will not be loaded. For the Macintosh, the paths are:
the folder the Eudora application is in
the sub folder Eudora
Stuff of the folder the application is in
the extensions folder in the
active system folder
Note that the Eudora folder (where Eudora stores mailboxes and related files, but not the application file) is not searched for plug-ins!
Building a translation DLL is straightforward because all that is needed is a DLL that implements a minimal subset of the API entry point functions using the standard "C" calling convention.
Eudora looks in a pre-defined set of directories for Windows DLLs that are EMS API plug-ins. This is done at start-up time. Each plug-in discovered is loaded and becomes active. For Windows the directories are:
The sub-directory plugins of the directory the Eudora .exe
file is in
The sub-directory plugins of the mail
directory
The fact that a particular DLL is an EMS API DLL is determined by checking that it implements the ems_plugin_version, ems_plugin_init and ems_translator_info functions.
Most of the functions in a plug-in, except the actual translation, can usually be implemented with a very small amount of code. These functions are also called much more frequently than the actual translation functions. Thus in some cases it may be advantageous to implement a translator in two parts, the smaller part which is loaded in memory all the time, and the larger part which is only loaded when translations are to be performed.
On the Macintosh, this second part can be another component, a shared library or a code fragment. Nothing about the API precludes any of these, and it is up to the translator author to decide which is to be used based on which platforms are to be supported.
A similar strategy may be adopted with Windows where the bulk of the translation function is implemented as a second DLL that is loaded only when a translation is being performed.
Macintosh:
pascal long ems_plugin_version(
short *api_version /* Place to return api version */
);
Windows:
extern "C" long WINAPI ems_plugin_version(
short FAR* api_version /* Place to return api version */
);
Eudora
calls this function once when it is loading the plug-in to determine what
version of the API it implements. The API version that should be returned is
defined in the API include files as EMS_VERSION. If the version number
does not match any of the versions implemented by the particular version of
Eudora, the plug-in will not be loaded and a message displayed tothe user.On the Macintosh, Eudora checks the version string in the thng resource as it is loading the plug-in.
Macintosh:
pascal long ems_plugin_init(
Handle globals, /* Handle to translator instance structure */
FSSpec *config_dir, /* Optional place to put config file */
StringPtr *user_name, /* Users full name from Eudora config */
StringPtr *user_addr, /* Users address (RFC-822 addr-spec) */
short *num_trans, /* Place to return num of translators */
StringPtr **plugin_desc, /* Return for string description of plugin */
short *plugin_id, /* Place to return unique plugin id */
Handle *plugin_icon /* Return for plugin icon suite */
);
Windows:
extern "C" long WINAPI ems_plugin_init(
void FAR*FAR* globals, /* Return for allocated instance structure */
char FAR* config_dir, /* Optional directory for config file */
char FAR* user_name, /* Users full name from Eudora config */
char FAR* user_addr, /* Users address (RFC-822 addr spec) */
short FAR* num_trans, /* Place to return num of translators */
char FAR*FAR* plugin_desc, /* Return for string description of module */
short FAR* plugin_id, /* Place to return unique module id */
HICON FAR*FAR* plugin_icon /* Return for translator icon data */
);
This
function is called once by Eudora as the plug-in is loaded. It is a good place
to do plug-in-specific initializations.For the Macintosh, the globals argument is a handle to a data structure holding the plug-in's global state. It is passed to all functions. The Component Manager takes care of carrying this between calls. If the plug-in is authored using SDK component main, ems-component.c, then this structure should be defined in usertrans.h. Otherwise the translator author must take care of allocation of this structure in their own main.
For Windows, the ems_plugin_init function must allocate this storage and return a pointer to it in the location pointed to by the globals parameter. Eudora will then pass this pointer into all other translation API calls for that plug-in-in. It should be de-allocated in the ems_plug_in_finish function.
The config_dir parameter is the path of a folder in which is the suggested location for a plug-ins own configuration data. This path varies as the Eudora folder and setting path varies, thus a plug-in's settings will vary with the Eudora settings if the user has multiple Eudora set ups on the system.
The user_name and user_addr are from standard Eudora set up. The user_name is the users's human name, and user_addr is the rfc-822 address the user has configured as their return address, or if no return address has been configured, it is the POP account.
For num_trans, the total number of translators should be returned. Translator IDs range from 1 to num_trans. The string plugin_desc should be a short string suitable for a splash or about screen and should include the plug-in version number. As with all strings returned to Eudora, on the Mac it must be allocated with NewHandle() and on Windows with the plug-ins internal memory allocator. Eudora may pass any of the last four parameters to the function as NULL indicating the data should not be returned.
Each plug-in must have a unique ID number and return it in the plugin_id parameter. These are available from an email auto-responder by sending a message to <emsapi-ids@qualcomm.com>. See section 2.3 for more details on the auto-responder.
The icon is shown in the plug-ins about box. On the Macintosh it should be an icon suite allocated with NewHandle(). For Windows it should be a 32x32 HICON allocated with the plug-ins own allocator function.
If the call to this function returns an error, Eudora will put up a dialog box indicating that initialization of the particular plug-in has failed.
Macintosh:
pascal long ems_translator_info(
Handle globals, /* Handle to translator instance structure */
short trans_id, /* ID of translator to get info for */
long *trans_type, /* Return for translator type, e.g., EMST_xxx */
long *trans_sub_type, /* Return for translator subtype */
unsigned long *trans_flags, /* Return for translator flags */
StringPtr **trans_desc, /* Return for translator string description */
Handle *trans_icon /* Return for translator icon suite */
);
Windows:
extern "C" long WINAPI ems_translator_info(
void FAR* globals, /* Pointer to translator instance structure */
short trans_id, /* ID of translator to get info for */
long FAR* trans_type, /* Return for translator type, e.g., EMST_xxx */
long FAR* trans_sub_type, /* Return for translator subtype */
unsigned long FAR* trans_flags, /* Return for translator flags */
char FAR*FAR* trans_desc, /* Return for translator string description */
HICON FAR*FAR* trans_icon /* Return for translator icon data */
);
This
function is called for each translator ID by Eudora as it builds its internal
lists of translators while it starts up. Note that any of the pointers to
places to return data may be NULL so Eudora does not have to request all the
details at once. Some items like the flags and types will be loaded once
initially, while others such as the icon may be retrieved each time it is
needed.The trans_id selects the particular translator in the plug-in for which the data is to be returned.
The translation type returned in the trans_type parameter must be one of the constants defined in the include file starting with EMST_. The trans_sub_type parameter is currently unused by Eudora and may be assigned any way the translator author wishes. The trans_flags parameter is very important configuration information supplied to Eudora. The flags are made up by "ORing" together a set of the constants starting with EMSF_. This specifies the contexts in which a translator can be called. The flags also indicate when a translator is called in MIME message structure traversal and whether the input and output are in canonical MIME format or not.
The description is a short string that is used for pull-down menu items. It is the only thing that identifies a translator on the menu so it should include something that indicates which plug-in it belongs to. An example might be "AcmeTrans Spanish-English."
The icon is used for presentation to the user in several places. On the Macintosh an icon suite should be returned and should be allocated using NewHandle(). For Windows, the icon should be a 16x16 HICON allocated with the plug-in's memory allocator.
Macintosh:
pascal long ems_can_translate_file(
Handle globals, /* Handle to translator instance structure */
long context, /* Context for check; e.g. EMSF_ON_xxx */
short trans_id, /* ID of translator to call */
emsMIMEtypeP in_mime, /* MIME type of data to check */
StringPtr ***addresses, /* List of addresses (sender and recipients) */
StringPtr *properties, /* Properties for queued translations */
StringPtr **out_error, /* Place to return string with error message */
long *out_code /* Return for translator-specifc result code */
);
Windows:
extern "C" long WINAPI ems_can_translate(
void FAR* globals, /* Pointer to translator instance structure */
long context, /* Context for check; e.g. EMSF_ON_xxx */
short trans_id, /* ID of translator to call */
emsMIMEtypeP in_mime, /* MIME type of data to check */
char FAR*FAR* addresses, /* List of addresses (sender and recipients) */
char FAR* properties, /* Properties for queued translations */
char FAR*FAR* out_error, /* Place to return string with error message */
long FAR* out_code /* Return for translator-specific result code
);
This
function checks to see whether a data item can be translated. It is called by
Eudora before every translation is attempted and in some cases to determine
whether a translation can be performed in a later context on some data. The
trans_id specifies which translator from the plug-in is being
called. The context parameter is a long with only one bit set to
indicate the context (e.g., : EMSF_ON_ARRIVAL, or
EMSF_Q4_TRANSMISSION). The MIME type of the input data is always
provided in the in_mime parameter. In a future version the message
header will most likely be passed in a buffer.Of the addresses passed, the first address is the From: address and the rest are the To:, Cc:, and Bcc:. These may be used for various purposes, but are particularly needed to aid looking up public keys for signing and authenticating. The addresses are passed as an array of strings in bunches of three. The first string in each bunch is the actual address (user@host.domain, or <addr-spec> from RFC-822), the second is the user's full name, and the third is the nickname. The full name and nickname may be absent (they may be NULL). The list is terminated when an address is NULL, but not when a nickname or full name is NULL. For example, the addresses are in addresses[0], addresses[3], addresses[6].... The addresses must be qualified with the full host name. The address data is always passed in the on-completion and on-transmission contexts, and is not passed in other contexts. Translators may ignore the addresses if they have no meaning for the particular translation. A future version of the API will distinguish the different address fields.
The properties are usually NULL, unless some properties have been specified by a call to ems_queued_properties(). In that case a string is passed.
If a string is returned in out_error, it will be displayed to the user in a dialog box. Error strings should be allocated with NewHandle() on the Mac and the plug-in's internal allocator on Windows.
Generally this function should check the MIME type and the context and return either EMSR_CANT_TRANS, EMSR_NOW or EMSR_NOT_NOW. It is common for a translator to return different values depending on the context, or to put off translation to another context and prevent other translators from running by returning EMSR_NOT_NOW. A check may also be performed on the addresses passed to the translator (e.g., for certificate validity).
Macintosh:
pascal long ems_translate_file(
Handle globals, /* Handle to translator instance structure */
long context, /* Context for translation; e.g. EMSF_ON_xxx */
short trans_id, /* ID of translator to call */
emsMIMEtypeP in_mime, /* MIME type of input data */
FSSpec *in_file, /* The input file name */
StringPtr ***addresses, /* List of addresses (sender and recipients) */
StringPtr *properties, /* Properties for queued translations */
emsProgress progress, /* Func to report progress / check for abort */
emsMIMEtypeP *out_mime, /* Place to return MIME type of result */
FSSpec *out_file, /* The output file (specified by Eudora) */
Handle *out_icon, /* Returned icon suite representing the result */
StringPtr **out_desc, /* Returned string for display with the result */
StringPtr **out_error, /* Place to return string with error message */
long *out_code /* Return for translator-specific result code */
);
Windows:
extern "C" long WINAPI ems_translate_file(
void FAR* globals, /* Pointer to translator instance structure */
long context, /* Context for translation; e.g. EMSF_ON_xxx */
short trans_id, /* ID of translator to call */
emsMIMEtypeP in_mime, /* MIME type of input data */
char FAR* in_file, /* The input file name */
char FAR*FAR* addresses, /* List of addresses (sender and recipients) */
char FAR* properties, /* Properties for queued translations */
emsProgress progress, /* Func to report progress / check for abort */
emsMIMEtypeP FAR* out_mime, /* Place to return MIME type of result */
char FAR* out_file, /* The output file (specified by Eudora) */
HBITMAP FAR*FAR* out_icon, /* Place to return icon representing result */
char FAR*FAR* out_desc, /* Returned string for display with the result */
char FAR*FAR* out_error, /* Place to return string with error message */
long FAR* out_code /* Return for translator-specific result code */
);
This
function performs the actual translation. Parameters not described here are
passed to ems_translate_file exactly the same as they are
passed to ems_can_translate_file and have exactly the same meaning as
described in the previous section. Note that ems_can_translate_file is
always called by Eudora before this function is called so the translator author
need not make the same checks here. This function will only be called if
ems_can_translate_file returns EMSR_NOW.The translator may behave different ways in different contexts. For example when verifying a signature in the automatic on-display context, it may choose to fail if the certificate necessary to verify is unavailable, but in the on-request context it may prompt the user to locate the certificate.
A progress/surrender function is supplied by Eudora to the translator. The translator should call the function periodically with an argument between 0 (just begun) and 100 (complete) to indicate its progress. The translator should check the return value from the function. If the value is 1 it should abort the translation, and if 0 it should continue. A translator may display its own progress status and not make use of the one which Eudora supplies. It should still call the progress function periodically with an argument of -1 to check for an abort. If the call to the progress function returns 1 indicating abort at any time, the translation must be aborted. In other words, the abort indication must never be ignored.
An empty output file is created by Eudora, and the name of this file is passed into the translator. The translator should write its output data into the file. If the translation is aborted Eudora will clean up and remove this file.
The translator must always return the correct MIME type of the translation output in the out_mime parameter even if the translator generates MIME. Thus, if the translator is unwrapping a MIME object it must parse the Content-Type: header and return its value in out_mime. This also implies that translators that generate MIME will return the resulting output MIME type in two places, in the actual data and in the out_mime parameter.
Except for translations in the on-request context, the input and output MIME types must be different in order to avoid an infinite translation loop. This can be done by adding a MIME parameter to the MIME type to indicate a translation has been performed. A good parameter name is x-eudora-translated, and a good value is the name of the translator and the context (e.g., spanish-english-on-arrival). Such a parameter will be ignored by all other MIME parsing. The translator should check for this parameter in its ems_can_translate_xxx function.
If out_desc is returned it will be displayed in the message window adjacent to the entity just translated along with some visual indication that it is tied to the entity. The icon returned in out_icon is treated the same way, and displayed next to the entity.
For most translations the out_code is ignored, but for translations of type EMST_SIGNATURE it should be one of the constants EMSC_SIGOK, EMSC_SIGBAD, or EMSC_SIGUNKNOWN to indicate the status of the signature. Eudora displays the bar that ties the icon and status message to the translated text differently, depending on the result of the signature verification.
For translations on message text, the temporary files are deleted immediately after the translation is complete. Attachments, however are not deleted until the user removes them. This will change when Eudora switches to using MIME storage internally.
Macintosh:
pascal long ems_translate_buf(
Handle globals, /* Handle to translator instance structure */
long context, /* Context for translation; e.g. EMSF_ON_xxx */
short trans_id, /* ID of translator to call */
emsMIMEtypeP in_mime, /* MIME type of input data */
unsigned char **in_buffer, /* Handle to buffer of data to translate */
long in_offset, /* Offset to start of input data in buffer */
long *in_buffer_len, /* Amount of input & returns input consumed */
StringPtr ***addresses, /* List of addresses (sender and recipients) */
SringPtr *properties, /* Properties for queued translations */
emsProgress progress, /* Func to report progress/check for abort */
emsMIMEtypeP *out_mime, /* Place to return MIME type of result */
unsigned char **out_buffer, /* Handle to buffer output should be placed in */
Handle *out_icon, /* Returned icon suite representing the result */
StringPtr **out_desc, /* Returned string for display with the result */
StringPtr **out_error, /* Place to return string with error message */
long *out_code /* Return for translator-specific result code */
);
Windows:
extern "C" long WINAPI ems_translate_buf(
void FAR* globals, /* Pointer to translator instance structure */
long context, /* Context for translation; e.g. EMS_ON_xxx */
short trans_id, /* ID of translator to call */
emsMIMEtypeP in_mime, /* MIME type of input data */
unsigned char FAR* in_buffer, /* Pointer to buffer of data to translate */
long FAR* in_buffer_len, /* Amount of input & returns input consumed */
char FAR*FAR* addresses, /* List of addresses (sender and recipients) */
char FAR* properties, /* Properties for queued translations */
emsProgress progress, /* Func to report progress/check for abort */
emsMIMEtypeP FAR* out_mime, /* Place to return MIME type of result */
unsigned char FAR* FAR* out_buffer, /* Eudora supplied output buffer */
long FAR* out_buffer_len, /* Out buffer size & returns amount filled in */
HICON FAR*FAR* out_icon, /* Place to return icon representing result */
char FAR*FAR* out_desc, /* Returned string for display with the result */
char FAR*FAR* out_error, /* Place to return string with error message */
long FAR* out_code /* Return for translator-specific result code */
);
The
buffer-based translate function is expected to be supported in API version
3.The buffer-based translation behaves similar to the file-based translation. The variance is in the way the data is passed and in the number of times it is called to perform a complete translation.
This function is called repeatedly by Eudora as it feeds the data to be translated to the translator. It is called repeatedly as long as there is input. When there is no more input, the function will continue to be called repeatedly with an input length of 0 until the output length returned is 0.
For Windows the input data is passed as a pointer to the input buffer. The length of the input data is passed as a pointer to a long. The translator need not consume all the input data. It should return the amount of data consumed in the long in which the original length of the input was given. For output, Eudora supplies the output buffer and guarantees it will be at least 8Kbytes. The actual length of the buffer is given in a long a pointer to which is passed. The translator should write its output into the buffer, and return the length of the output written in the long the buffer size was passed in. When Eudora calls the function with an input length of zero and the translator returns an output length of 0, the translation is considered complete. If the function return value is anything but EMSR_OK, the translation will also be considered complete.
The Macintosh is similar to Windows with some differences in the data structures. On input a Handle to the input buffer is passed along with an offset into the buffer where input actually starts. This saves significant copying and reallocting of data when the input is only partially consumed. The size of the output buffer can be obtained with GetHandleSize(), and the size of the output buffer filled in is returned to Eudora by calling SetHandleSize().
Macintosh:
pascal long ems_plugin_finish(
Handle globals /* Handle to translator instance structure */
);
Windows:
extern "C" long WINAPI ems_plugin_finish(
void FAR* globals /* Pointer to translator instance structure */
);
This
gives the plug-in a chance to free allocated memory, saved state information,
etc. Windows translators should de-allocate the globals memory, but Macintosh
translators should not.
extern "C" long WINAPI ems_free(
void FAR* mem /* Memory to free */
);
This
is called by Eudora to free data structures passed from a plug-in to Eudora.
This data includes strings, addresses, and the MIME type data structure. This
is not used on the Macintosh since all data on it are Handles allocated with
standard functions.
Macintosh:
pascal long ems_plugin_config( Handle globals, /* Handle to translator instance structure */ FSSpec *config_dir, /* Optional place to put config file */ StringPtr *user_name, /* Users full name from Eudora config */ StringPtr *user_addr /* Users address (RFC-822 addr-spec) */ ); Windows:
extern "C" long WINAPI ems_plugin_config( void FAR* globals, /* Pointer to translator instance structure */ char FAR* config_dir, /* Optional directory for config file */ char FAR* user_name, /* Users full name from Eudora config */ char FAR* user_addr /* Users address (RFC-822 addr spec) */ );
The icon and name of the plug-in will appear in a special plug-ins pane selected from the message plugins item under the special menu. When the user clicks on the icon, this function above will be called. The plug-in should put up its settings panel, interact with the user and store the result.
The config_dir parameter is the full path of a suggested directory for writing configuration files to. The plug-in should read and write it's won configuration files. Eudora only suggests a directory.
The user_name parameter is the user's plain name as entered in the Personal Information section of Eudora's setup dialog. The user_addr passed is the return address if there is one explicity given in the Eudora set up dialogue, otherwise it is the POP account.
Macintosh:
pascal long ems_queued_properties( Handle globals, /* Handle to translator instance structure */ long context, /* EMSF_Q4_COMPLETION or _TRANSMISSION */ short trans_id, /* ID of translator to call */ short *selected, /* Returned flag - is trans selected? */ StringPtr **properties /* ASCII string encoded properties */ ); Windows: extern "C" long WINAPI ems_queued_properties( void FAR* globals, /* Pointer to translator instance structure */ long context, /* EMSF_Q4_COMPLETION or _TRANSMISSION */ short trans_id, /* ID of translator to call */ short FAR* selected, /* Returned flag - is trans selected? */ char FAR*FAR* properties /* ASCII string encoded properties */ );
For queued translations the user selects the translation possibly including some parameters about it, at a different time than the translation is performed. This function allows the parameters to be stored with the message while it is in the queue.
This function is optional. If it is not supplied, queued translations will be toggled on and off by checking the icon in the composition bar. If this is function is present it will be called when the user clicks the icon in the composition bar. The function is passed the usual parameters to identify the translator and context. When called, this function may put up a dialogue and interact with the user.
The context parameter is as usual the context in which the translation is going to run.The trans_id parameter specifies the paritcular translator in the plug-in.
This function may return two values. The first is a short the value of which is taken as a boolean to indicate to Eudora whether the translation is selected. If the returned value is 1, a check mark will be displayed next to the translator on the menu, and the translation will be performed at the appropriate time. The second is a string in which the translator may return the state that it wants to store for this message until the translation is performed. This string will be passed to the translate function. The string must be printable ASCII characers from "!" (0x41) to "~" (0x7e) and must not contain any commas (0x2c). The string must also be less than 100 bytes. The translators may encode binary data in the string if desired (e.g., with base64 encoding).
If the user has selected EMST_PREPROCESS and EMST_SIGNATURE translations, and an EMST_COALESCED translation is available, it will be called instead as described previously. The properties of the two translators will be passed to the EMST_COALESCED translator concatenated and separated by a comma. The EMST_SIGNATURE translator's parameters will be first. This way nothing special need be done by the translators a queue time. They each set their parameters as they wish.
August 20, 1996
* Incremented API version number to 2
* Implemented the settings dialogue
* Implemented queued_properties
* Added properties parameter to ems_can_translate(), ems_translate_file() and ems_translate_buf()
* Added user name, address and configuration folder to ems_plugin_init() call
* Changed name of ems_can_translate_file() to ems_can_translate() and removed a couple of parameters.
July 19, 1996
* Clarified features in version 1 vs. future versions
* Completed name change from tlapi to ems api
* Added description of ID allocating auto responder
* Major clarifications to use of MIME format and type
* Added about box to list loaded plug-ins
* Clarifications on the translation process
* More consistent terminology and notation
* Specifies Windows icon format
* Specifies Windows plug-in search directories
* Abort return code added, plug-ins required to abort when told to do so
* Moved MIME background to an appendix
* Dropped the buffer version of ems_can_translate
May 22, 1996
* Removed DOES_MIME_LEAVES since it was unused and meaningless
* Progress function now works.
* Described some future additions
* on-request translators now checks MIME types
* More documentation clarifications and rewording (MIME-related stuff)
* Described planned implementation of buffer-based translation
* Significant support for Windows added (but Windows SDK isn't available yet)
* Windows allocator function added
April 1996
* Switch to separate Macintosh and Windows API definitions
* Removed OP code and lookup function
* Added calling interface details for Mac and Windows
* Added export warning for translation authors
* Page numbering and minor wording changes
* Major clarifications
* Added module_version function
* Removed de-allocator and version arguments from module_init
* Added module icon argument to module_init
[Component] Inside Macintosh: More Macintosh Toolbox. Addison Wesley 1993.
[DLL] Windows SDK that describes DLL's
[Crocker] CROCKER, D. Standard for the format of ARPA Internet Text Messages. Internet Engineering Task Force, RFC 822. 1982.
[MIME] BORENSTEIN, N. AND FREED, N. MIME: Multipart Internet Mail Extensions. Internet Engineering Task Force, RFC 1521. 1993
[FREED] FREED, NED, ET AL. Security Multipart for MIME: multipart/signed and multipart/encrypted. Internet Engineering Task Force, RFC 1847. 1995
[Lang] ALVESTRAND, HARALD. Tags for Identifcation of Langages. Internet Engineering Task Force, RFC 1766. 1995
[Enriched] RESNICK, PETE AND WALKER, AMANDA. RFC-1896, The text/enriched content type. Internet Engineering Task Force, RFC 1896. 1996
Appendix A - A brief introduction to MIME
MIME (Multipart Internet Mail Extensions) [MIME] is the Internet standard for describing objects in Internet e-mail. It is also used in other applications on the Internet such as the World-Wide Web. The MIME standard has three main functions. It provides type tagging information for e-mail messages and their parts. It provides a format for representing object types and message structure, and it provides transfer encoding for safely passing 8bit text and binary data through 7bit text-only data paths.
Content-Type: MULTIPART/MIXED; BOUNDARY="-559023410-851401618-831602781=:25682" ---559023410-851401618-831602781=:25682 Content-Type: TEXT/PLAIN; charset=US-ASCII This is a little text part of the message ---559023410-851401618-831602781=:25682 Content-Type: IMAGE/GIF; charset=US-ASCII Content-Transfer-Encoding: BASE64 Content-Disposition: attachment; name="apipict.gif" IC8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09 eHRlbmRlZCBNZXNzYWdlIFNlcnZpY2VzIEFQSSBTREsgMS4wYjIgKE1heSB4 eCAxOTk2KQ0KICAgIFRoaXMgU0RLIHN1cHBvcnRzIEFQSSB2ZXJzaW9uIDEN CiAgICBDb3B5cmlnaHQgMTk5NSwgMTk5NiBRVUFMQ09NTSBJbmMuDQogICAg ---559023410-851401618-831602781=:25682--A small example of a MIME e-mail message is shown above. It is a two-part message with the first part being some text and the second part being an attachment. The second part is a GIF image with base64 encoding so the binary GIF image can be passed through 7-bit channels.
Each MIME type has a top level type, a sub-type and optional parameters. The top-level content types are relatively fixed and currently number seven: text, application, multipart, message, image, audio and video. The multipart type is of particular importance because it is a container for any number of MIME objects, thus MIME allows nested structuring of message objects. There are many sub-types for each top-level type. New sub-types can be registered as long as there is a document giving a basic description of them. The actual type information is usually expressed as ASCII text in the form type/sub-type. The type may also include parameters which allow specification of further details about the types. The set of parameters is completely dependent on the sub-type, though some are common to more than one sub-type. Two common parameters are character-set and language.
In addition to defining a typing scheme, MIME very precisely specifies data formats for representing the type data and for creating a data object that combines the actual content data and the type information.
Because MIME objects are commonly transferred via Internet e-mail, often a 7bit text-only path, the MIME standard also includes an encoding scheme for expressing arbitrary data as 7bit text with limited line lengths. This is known as "content transfer encoding".
Because MIME is used to pass objects over the network between unlike computing platforms (e.g., Macintosh and Windows), it defines a notion of a canonical format for data objects. This is a format for a data object of a specific type that is either common to the platforms it is used on, or is defined to be the interchange format for the object across platforms. The most important canonical format is for text objects because the end-of-line delimiter for text files varies between major computing platforms. Canonical text in MIME messages has lines separated by the CRLF (carriage return and line feed) pair and does not include CR or LF except at the end of a line.
A canonical on-the-wire formatted MIME entity is an octet stream (which may be in the process of being transmitted, in a file on disk, or in a memory buffer) representing message objects in their canonical format tagged with MIME types.
It possible to define proprietary MIME types for specific translator applications. It is also possible to go through the standards process to define new MIME types to be used widely on the Internet. The types enable translators to easily and efficiently recognize data on which they wish to operate.
The reader is referred to the MIME standards documents [MIME] for further details.
[an error occurred while processing this directive]