Copyright © 2003, The University of Texas at Austin.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, with no Front-Cover Texts and with no Back-Cover Texts.The Cascabel Framework is distributed under the terms of the GNU General Public License: This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
Issues, be they bugs, requests, purchase orders, donations, or whatever, need tracking. Unfortunately, no one seems to make little radio collars for them. As a result, we need to create programs that maintain information about issues. That is what Cascabel is for.
Cascabel is a ticket tracking system. It handles tickets, which maintain information about specific issues. A ticket may be something like a purchase order, a bug report, or a request for support. The issue is assigned an identifier, or ticket id (an integer), and all communications about the issue (that pass through the Cascabel system, obviously) are logged and potentially forwarded to everyone associated with the ticket. Also, status information about the ticket is kept, such as its state (helpfully called the "status" in Cascabel) and the times it was created and last updated.
These tickets are organized in queues. The tickets in a queue should be related, like purchase requests, bug reports, and so on. The people who handle the issues, called staff members, are associated with the particular queues. In most Cascabel queues (depending on the interfaces built with the Cascabel framework, of course), the staff members for a queue can view and edit the information about every ticket in the queue.
The life-cycle of a ticket is something like:
Cascabel requires other packages to function:
sendmail program for sending mail.
Cascabel is configured using the configure script included
with the distribution. Check the README file in the
distribution for up-to-date information. In general, in addition to
the usual configure arguments, you will need to supply:
Once its requirements are met and Cascabel is configured, built, and installed (in the normal, configure-make-make install way), you need to:
The information about tickets may be more or less confidential. Cascabel keeps all of the information in a MySQL database, and keeps this database secured by a single SQL password. The password, along with the other information needed to contact the database, is kept in a file that is protected by Unix file permissions--only the special user identified when Cascabel is installed is allowed to read the file. In this document, the user account is called the Cascabel user.
Cascabel programs which need to contact the database must be run
setuid to the Cascabel user. Since many Unixes such as Unix do not
allow Python scripts to be setuid, a wrapper program, written in C, is
used to call the actual script. This program selects the script to
run based on it's argv[0] argument--a symbolic link, named
after the script in your PATH, to the wrapper program makes the
connection. The wrapper program looks in a specific directory
(created during Cascabel's installation) for the script to actually
execute.
Thus, Cascabel tries to protect the information about tickets, but can only do so with the help of the interfaces. Those programs make the choices about what information to expose to whom.
Note that the scripts connect to the MySQL database over a network--this connection may be insecure.
In about 1996, the UT CS Department needed a system to track purchase requests. We looked around and came up with req 1.2.7, by Remy Evard. Req was "an email-based request tracking system." It satisfied our needs (mostly) for a number of years.
Later, we decided we needed a system to track shop (hardware support) requests. Req did not handle multiple queues, but a possible replacement system, RUST, did. RUST, however, was poorly written. (For example, its original file locking system meant a command paused for at least a second every time it ran. Also, RUST had about three subsystems for sending mail, only one of which called sendmail--the others would not handle MX DNS records nor queueing mail for later delivery.) It did not replace req, but we used it for shop requests for quite a while.
After trying to clean up RUST, I decided it would be simpler to just write my own damn tracking system, which became Cascabel. Rather than using flat files, like req and RUST, I chose to base the design around a SQL database, picking MySQL. The combination of Python as an implementation language and MySQL, plus some serious napkin-designing made Cascabel relatively small and simple, as well as flexible.
When we wanted to add CGI interfaces for the queues, I decided that Python was probably not the right choice--start-up latencies, don't you know. I chose PHP and simply re-created the Cascabel queue operations in PHP, which was fast and easy.
Nowadays, there are other tracking systems, such as RT, which provide much better functionality and support than the options that I looked at before starting Cascabel. If I were starting now, I would probably use RT. On the other hand, Cascabel has been very satisfactory, and is a bit more flexible than RT.
Cascabel stores all of the data for all of the queues (including as much metadata as is convenient) is a SQL database. The currently supported database manager is MySQL; although it would be some work to add support for other DBMS, Cascabel is designed to allow for that and it should be reasonable trivial.
Cascabel is intended to be very flexible, particularly regarding the information stored about tickets by differing queues. Creating each queue requires adding at least one table to the database. This new table contains the individual ticket status information for the tickets in the queue.
This section describes each of the tables used by Cascabel. (It does
not show the indices used in the tables. For that, check the
initcascabel script. See initcascabel.
The queues table contains much of the metadata about each queue managed by Cascabel. The fields are:
queue
incoming
outgoing
subjpattern
subjformat
printf-like string used to create outgoing subject
headers.
receipt
remoteaction
The SQL schema for the table is:
CREATE TABLE queues (
queue CHAR(64) NOT NULL PRIMARY KEY,
incoming VARCHAR(64),
outgoing VARCHAR(64),
subjpattern CHAR(64),
subjformat CHAR(64),
receipt TEXT,
remoteaction ENUM('True', 'False')
);
The allowedstatus provides more metadata about each queue: The allowable values of the status field.
The SQL schema for the table is:
CREATE TABLE allowedstatus (
queue CHAR(64) NOT NULL,
status CHAR(64) NOT NULL
);
queue
status
The mail filters used to variously ignore incoming mail messages.
The SQL schema for the table is:
CREATE TABLE mailfilters (
queue CHAR(64),
pattern VARCHAR(255),
type ENUM('Ignore', 'Nobody', 'Reject') DEFAULT 'Ignore'
);
queue
pattern
type
By default, the mailer-daemon address is Ignored.
INSERT INTO mailfilters SET pattern='mailer-daemon';
All actions and mail messages regarding any ticket in the queue are permanently recorded in the log table, under the queue and ticket id.
The SQL schema for the table is:
CREATE TABLE log (
queue CHAR(64) NOT NULL,
id INTEGER NOT NULL,
timestamp TIMESTAMP,
entry TEXT NOT NULL
);
queue
id
timestamp
entry
It is possible for a ticket to be either merged with another ticket in the same queue or (although this is currently unimplemented) moved to another queue. The synonyms table handles the mapping.
The SQL schema for the table is:
CREATE TABLE synonyms (
squeue CHAR(64) NOT NULL,
sid INTEGER NOT NULL,
dqueue CHAR(64) NOT NULL,
did INTEGER NOT NULL
);
squeue
sid
dqueue
did
The staff are specially singled-out users: They are assumed to get mail about tickets either automatically from forwarded messages or through queue-specific processing. As a result, Cascabel tries very hard to make sure that staff addresses for a queue are not inserted into the list of users for any ticket in the queue. They also have a password assigned, for authenticated CGI applications. For Python command-line programs, the userid of the person running the program is added to the default mail domain and the result is used to look for an entry in the staff table.
A person can be a staff member of many queues. The staff record is always the same; the queuestaff table is used to indicate which queues an address is a staff member for.
The SQL schema for the staff table is:
CREATE TABLE staff (
address VARCHAR(255) NOT NULL,
password VARCHAR(255),
staffid INTEGER NOT NULL AUTO_INCREMENT
);
address
password
staffid
The SQL schema for the queuestaff table is:
CREATE TABLE queuestaff (
queue CHAR(64) NOT NULL,
staffid INTEGER
);
queue
staffid
The users table is used to record the user email addresses associated with each ticket in every queue.
The SQL schema for the table is:
CREATE TABLE users (
queue CHAR(64) NOT NULL,
id INTEGER NOT NULL,
address VARCHAR(255) NOT NULL
);
queue
id
address
Every ticket needs a home. Or, at least, some place to hang its status information. In Cascabel, every queue has its own table of ticket status information, although each of these tables must have a minimal set of standard fields. This approach is the key to Cascabel's flexibility--some queues will need very specialized information about each ticket and rather than trying to anticipate all of the possible fields, Cascabel allows them to be extended from a base set as needed.1
Each table should be called queueticket; i.e. the queue
name followed by the word "ticket".
The SQL schema below describes the table for the "cascabel" queue, which is an example and testing queue included in the basic Cascabel configuration. It illustrates the minimum set of columns.
The SQL schema for the table is:
CREATE TABLE cascabelticket (
id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
status CHAR(65) NOT NULL DEFAULT 'open',
subject VARCHAR(255),
created DATETIME,
updated DATETIME
);
id
status
subject
created
updated
Additional fields are added as needed and processed by the queue-specific code which uses the framework. There should be some examples around, near wherever you found Cascabel.
It would be fairly trivial to add additional tables associated with queues, assuming you avoid naming conflicts. Thus, for example, a queue could have tickets of different types, where each type of ticket had its own set of extra fields. The complexity of the application, however, might make extra tables unworkable.
The major operations of the framework revolve around the connection to the database. These operations include requesting or updating information about queues, tickets, users, or staff members.
Not all of the operations are supplied by all of the interfaces. For example, since the PHP interface handles unauthenticated web interactions, it does provide the login and changepassword operations. The Python interface currently does not since it is used for already-authenticated command-line interactions. On the other hand, the PHP interface does not provide the mail support operations or some of the other operations that are not needed by web interfaces. And, of course, neither interface is really complete--some operations have simply not been implemented.
These operations are currently provided by the
CascabelMySQL.py, CascabelMySQLExpressions.py, and
CascabelMySQL.phpi, with the interface modules for accessing
them being Cascabel.py and Cascabel.phpi.
There are two ways of getting ticket information from the database.
First, if you have the ticket id, all the information can be recovered
directly and quickly. Second, if you wish to find one or more tickets
matching some criteria, you will need to create a predicate describing
the criteria. These predicates can be given to the lstickets
and getlog methods, which return a list of ticket records and
log entries, respectively. The predicates are built of a thin layer
of functions over the underlying SQL. The database SQL operators that
Cascabel provides are:
| And predicate [predicate]... | Function |
| Or predicate [predicate]... | Function |
And and Or are boolean operators and take either
multiple arguments (Python) or an array of arguments (PHP) and combine
them.
|
| Not predicate | Function |
Not is the unary boolean operator.
|
| IsNull field | Function |
Is true when field is null (i.e. empty, not having a value).
|
| True | Function |
| False | Function |
True and False are constants.
|
| Equal field value | Function |
| NotEqual field value | Function |
| AtMost field value | Function |
| AtLeast field value | Function |
| LessThan field value | Function |
| MoreThan field value | Function |
| Rlike field pattern | Function |
Compare field with value. The field should be a
string giving the column name and the value is an appropriate
value (i.e. an integer, or a string). The pattern for
Rlike is a regular expression.
|
The basic queue operations provide meta-data about a queue. The normal meta-data consist of the information from the queues table and the list of allowed status for each queue from the allowedstatus table.
| Connection [host user password] [debug] | Function |
|
Open a connection to the database (on host, using user and
password to make the connection). The arguments host,
user, and password are optional; if they are not provided,
the Cascabel |
| getqueue queue | Method on Connection |
|
Return the information from the queues table associated with queue. |
| getqueues | Method on Connection |
|
Return all of the queues table information about every queue in the database. |
| lsstatus queue | Method on Connection |
|
Return the information from the allowedstatus table, with the allowed status for queue. |
Filters are regular expressions matched against email addresses. The filter types are "Nobody", "Ignore", and "Reject".
| lsfilters queue [type] | Method on Connection |
|
Return information from the mailfilters table matching either the queue or or with a null queue. If the type is present, the filters are limited to that type. |
The ticket operations include creating a ticket, retrieving the information about a ticket or about all the tickets in a queue, updating a ticket, and merging tickets.
| mkticket queue info | Method on Connection |
|
Create a new ticket in queue with the fields specified in info. Returns the id number of the new ticket. |
| getticket queue id | Method on Connection |
|
Return the status information about ticket id in queue. Generally, the status information will be a dictionary where the keys are columns from the database table. The getticket method checks the synonyms table to find the actual ticket information. |
| lstickets queue predicate [order] [user] | Method on Connection |
|
Return a list of ticket status information. The tickets will be from queue, match predicate, be in order according to the order database column. If user is true, the ticket table will be joined with the users table, to find tickets associated with a given user. The user's email address should be part of the predicate. The lstickets method does not check the synonyms table; this method is used to generate a list of existing tickets. |
| setticket queue id info | Method on Connection |
|
Update the status information for ticket id in queue. The info should be a dictionary mapping from database columns to new values. This method does check that an updated status is allowed by the queue. |
| update queue id [time] | Method on Connection |
|
Set the last-updated time of ticket id in queue to time, if present, or the current time, otherwise. |
| mvticket source-queue source-id dest-queue dest-id | Method on Connection |
|
Merge ticket source-id from source-queue into dest-id in dest-queue. dest-id should already exist. |
A staff member is an email address that is allowed to edit the status of a ticket. As a result, they need to be tracked more closely than the normal user addresses.
| mkstaff queue address [password] | Method on Connection |
|
| lsstaff [queue] [address] | Method on Connection |
| Return a list of dictionaries with keys "address", "password", and "queue" for staff entries. If the queue is specified, the list is limited to that queue; if address, that staff address. Giving both provides an easy test for whether the address is a staff member for queue. If neither is given, lsstaff generates a list of all staff addresses. |
| rmstaff address [queue] | Method on Connection |
| If queue is given, remove the queue entries for address from the queuestaff table. Otherwise, remove address from the staff table and remove all corresponding queuestaff entries. |
| login queue address password | Method on Connection |
| Authenticate staff address in queue with password. Returns true or false. |
| changepassword address password | Method on Connection |
| Change the password entry for the staff address to password. |
Users are addresses which are not staff members, but which are involved with particular tickets. These do need some managing, particularly when a non-existent address gets inserted into the database.
Cascabel tries very hard to prevent staff addresses for a queue from getting listed as users on tickets in the queue. This is part of the "don't send extra copies of mail" effort.
| mkuser queue id address | Method on Connection |
| Add address to the user table for ticket id in queue. |
| lsusers queue id | Method on Connection |
| Return the user entries associated with ticket id in queue. |
| rmusers ids [queue] | Method on Connection |
| Remove addresses ids from the users table, limited to entries for queue if it is present. |
| lsuseraddresses [queue] | Method on Connection |
| Return a list of user addresses, either all unique addresses in the table or only those for queue, if it is present. Deprecated |
Log entries record information from mail messages and status changes about a ticket. Every event should be mentioned here.
For mail message entries, all of the headers are preserved, to handle MIME messages, for example.
| getlog [queue] [id] [predicate] | Method on Connection |
Return the log entries for queue and id or matching
predicate. The legal combinations are:
|
| log queue id entry [time] | Method on Connection |
| Log entry for ticket id in queue at time (or the current time). |
One of the primary purposes of Cascabel is to manage communication about issues, and the primary tool for communication in this system is electronic mail. Cascabel fundamentally provides an archived mailing list, where the information regarding a particulary ticket is collected in the logs.
There are two ways mail about existing tickets can be handled:
The mail handling functions and classes are to be found in the
CascabelMail.py Python module.
Cascabel, unlike some other systems, makes no prentensions about being a mail transport agent. It uses the sendmail program for all mail messages sent from the Python module. (There is no similar PHP module--use the standard PHP mail() function.)
| send message addresses | Function |
| Send the formatted message to the list of addresses, using sendmail. |
| resend message sender addresses | Function |
| Resend message to the list of addresses without altering it, except by adding the "Resent-From: sender" and "Resent-To:" headers. |
The basic mail handling module provides a number of functions for
dealing with email headers. While these are primarily used in the
CsacabelMail.py module, most of the queue-specific mail
handling scripts use a subclass of MailHandler, which may need
to use these functions.
| filterheader field headers | Function |
| Return headers with any field headers removed. |
| replaceheader field value headers | Function |
| Replace the instances of field headers with a "field: value" header in headers, returning the result. |
| filterfromline headers | Function |
| Return headers with the "From " line removed. The from_ line is added by the mail transport agent when the message is being stored to contain the envelope information. |
| headervalues field headers | Function |
| Return a list containing the values of the header field from headers. |
| headervalue field headers | Function |
Return the first value given by headervalues.
|
| Subject headers | Function |
| The value of the Subject header. |
| XCascabel | Function |
| The values of any application-specific X-Cascabel headers. |
| Comment | Function |
| The values of any Comment headers. |
| addressesfromheaders field headers | Function |
| Return the list of addresses given in header field. |
| From | Function |
| Addresses from the From header. |
| To | Function |
| Addresses from the To header. |
| CC | Function |
| Addresses from the CC header. |
| Sender | Function |
| Addresses from the Sender header. |
| quotebody body | Function |
| Quote each line of the body of an email message with " >" strings. |
The MailHandler class provides the basic functionality for
dealing with incoming mail. The functions it provides are broken up
into several methods, to allow subclasses for specific queues to take
queue-defined actions under queue-defined circumstances.
| MailHandler queue | Function |
Return a MailHandler instance for queue.
|
| SilentMailHandler queue | Function |
Return an instance of a subclass of MailHandler which does not
send or forward mail. This class is useful for processing an existing
mail log and for testing.
|
| close | Method on MailHandler |
Close the database connection used by the MailHandler.
|
| incoming message | Method on MailHandler |
Process an incoming mail message:
|
| hasid subject | Method on MailHandler |
| Check to see if the subject matches the subject/ticket id pattern in the queues table. |
| returnunknown pseudo-id | Method on MailHandler |
| Return the message to the sender, indicating that no ticket pseudo-id exists. |
| receipt id | Method on MailHandler |
| Send a message to the originator indicating that ticket id has been created. The format of the message is given by the receipt column of the queues table. |
| forward id | Method on MailHandler |
| Pass the message on to the staff and users. |
| filter headers [type] | Method on MailHandler |
| Check the mail headers against the filters in the database. type defaults to Ignore. If the message is filtered, it is resent to the queue's outgoing address, to avoid losing mail without warning. |
| remoteactions | Method on MailHandler |
Handle action-at-a-distance. The format of the header is
"X-Cascabel: <cmd>". The two possible remote actions are:
|
Cascabel provides a number of utility functions that are needed by
many queues and interfaces. These functions are found in the
Cascabel.py and Cascabel.phpi modules.
| age date [now] | Function |
| Return a string describing the approximate difference between age and now, where now defaults to the current time. The string will be something like "4 mins". |
| cannonical address | Function |
| Ensures address is a valid (more or less) email address, by checking for an `@` character. If one is not found, the default domain (as given when configuring Cascabel) is appended to address, separated by `@`. |
| thisuser | Function |
| Return the cannonical address of the user running the program. Obviously, this is only valid in the Python implementation. It can be used to test if the user running the program is a staff member, or to use the user running the program as a default wherever a user is needed. |
Unrelated to Cascabel, but useful in many of the CGI interfaces written using PHP, Machine.phpi and TemplateCache.phpi are PHP modules providing a session-based state machine and a simple template mechanism.
The session-based state machine supports writing a CGI application as
a collection of state machine transitions. In this approach, the
states are represented by displayed web pages. The transitions are
instances of class Transition. (This mechanism is related to the idea
of using continuations for web programming, but is performed manually
and is less powerfully.) The instances of Transition are created
before displaying a page and saved in the session, with a transition
identifier inserted into the page (via an instance of TransitionKey).
When a user submits a form, a hidden field in the form contains a
transition identifier. The transition is recovered from the session
and it's execute method is called with the input fields from
the form.
The transitions in the session store are kept for the lifetime of the session, (hopefully) allowing the user to navigate the CGI application using any mixture of browser back buttons, form buttons and links, and multiple windows. The programmer using Machine will obviously need to take into consideration any transactional semantics needed in the application.
The following example should illustrate the basic approach:
class Search extends Transition {
function Search ($id) { $this->id = $id; }
function execute ($mc, $rq) {
echo search_form($mc, $this->id, new Query);
return 'search';
}
}
In the example, a Search instance is created with an id, which
records the user's identity associated with the session. This
transition leads from a basic menu to a state showing a search form.
When the transition is executed, the search form is printed, based on
the state machine, the user identity, and a new, bare Query (which
will be filled in from the form). The return value identifies the new
state. (The state names other than "start" are for documentation
purposes.)
To continue the example, the function search_form gets a
template, replaces the message and action substitutions, inserts the
query information, and inserts a transition key associated with a
Transition that lists the tickets matching the query.
function search_form ($mc, $id, $q, $msg="") {
$t = $mc->get_template('search-form');
$t->replace('message', $msg);
$t->replace('action', $_SERVER['PHP_SELF']);
$t->replace_all($q->values());
$k = $mc->set_transition(new ListTickets ($id, $q));
$t->replace('k', $k->as_form_field());
return $t->show();
}
| Machine | Function |
| The state machine tracks the state and the set of transitions that are available. Creating a state machine object restores the information from PHP's session and executes the next transition, which may be either a default transition (the initial transition in a new session), or a transition identified from the CGI request. |
| initial_transitions | Method on Machine |
|
Create an initial transition table. The transition table is an array
mapping transition identifiers to instances of subclasses of
Transition; the initial table should map the "start" transition
identifier to a default transition.
The following example is the body of a basic
return array("start" => new ToAuth);
In this example, ToAuth is a subclass of Transition, whose constructor
does not take any arguments.
|
| set_transition transition | Method on Machine |
| Records the transition in the session, returning an instance of TransitionKey associated with the transition. |
| shutdown | Method on Machine |
| Clear the transition table. |
| Transition | Function |
| Creates a Transition. The constructor for a subclass should take as arguments any information that the transition should preserve until it is invoked. |
| execute machine request | Method on Transition |
The execute method is invoked by the state machine when the
transition is taken. Its arguments are the state machine object
(an instance of Machine) invoking the method, and the CGI
request (PHP's REQUEST variable) from the user.
|
When the set_transition method of Machine is invoked, the
result is a TransitionKey, identifying the Transition that has been
stored in the session. The TransitionKey can be used to create either
a hidden form field (for use in a form) or a CGI GET query string (for
use as a simple link).
| as_form_field | Method on TransitionKey |
Returns a string like
<input type="hidden" name="k" value="id">
The id value can be used to restore the transition from the
session store.
|
| as_query | Method on TransitionKey |
Returns a string like
k=id
suitable for use (after a "?") in a URL. The id can be used
to restore the transition from the session.
|
Templates are used to separate the presentation of the CGI application from the code implementing it. The templates are kept in separate files which are read by the application as needed. The templates have positions in them for substitutions to be performed by the application.
In order for templates (for, say, table rows) to be reused many times in the same program execution, the templates are cached in the TemplateCache instance.
| get_template name | Method on TemplateCache |
Returns a Template object containing the template identified by
name. The file the template is taken from is
./templates/name.tmpl.
|
The Templates returned have two functions which give replacement
texts, replace and replace_all. The templates should
have substitution points given by %name%; i.e. the name
of the substitution point surrounded by percent signs.
| replace name text | Method on Template |
| Replaces the all occurances of the substitution name with text. |
| replace_all dict | Method on Template |
The dict should be an array mapping names to texts;
replace_all performs the same operation as multiple calls to
replace.
|
| show | Method on Template |
| Return the contents of the template with all of the substitutions performed. |
Cascabel comes with a number of scripts. Each has a man page which you should examine for specific details.
The cascabel-admin script provides a command-line interface
for managing the Cascabel queues. At the time of this writing, it is
limited to:
cascabel-admin(1) man page for more information.
The cascabel-config script is used to provide access to the
configuration information given when installing Cascabel. This script
is primarily used while configuring individual queue packages.
The MySQL/makecascabel script sets up the Cascabel database and
creates the Cascabel user in the DBMS.
The MySQL/initcascabel script creates the basic set of Cascabel
tables in the database.
The cascabel-query, cascabel-show, and
cascabel-mail scripts are examples, used with the sample
cascabel queue. The sample queue is set up in the database by the
makecqueue MySQL script.
Other examples, including a near-direct translation of Req and the programs and what-not for the other queues from UTCS, should be available from the Cascabel home page.
Cascabel keeps the SQL database contact information including the password in a file that is readable only by the user identified when Cascabel is configured. The format of the file is:
hostname:database:password
Being able to read this file involves using the
cascabelwrapper program, which is installed setuid to the
Cascabel user. This program uses the name it is invoked under to
switch between the Python scripts--a symbolic link to
cascabelwrapper named "foo" will try to execute the Python
"foo" script in the Cascabel library's bin directory.
See the cascabelwrapper(1) man page for more information.
addressesfromheaders: Mail headers
age: Utility Functions
And: Database operations
as_form_field on TransitionKey: TransitionKey
as_query on TransitionKey: TransitionKey
AtLeast: Database operations
AtMost: Database operations
cannonical: Utility Functions
CC: Mail headers
changepassword on Connection: Staff operations
close on MailHandler: The MailHandler
Comment: Mail headers
Connection: Basic queue operations
Equal: Database operations
execute on Transition: Transition
False: Database operations
filter on MailHandler: The MailHandler
filterfromline: Mail headers
filterheader: Mail headers
forward on MailHandler: The MailHandler
From: Mail headers
get_template on TemplateCache: TemplateCache.phpi
getlog on Connection: Log operations
getqueue on Connection: Basic queue operations
getqueues on Connection: Basic queue operations
getticket on Connection: Ticket operations
hasid on MailHandler: The MailHandler
headervalue: Mail headers
headervalues: Mail headers
incoming on MailHandler: The MailHandler
initial_transitions on Machine: Machine
IsNull: Database operations
LessThan: Database operations
log on Connection: Log operations
login on Connection: Staff operations
lsfilters on Connection: Mail support operations
lsstaff on Connection: Staff operations
lsstatus on Connection: Basic queue operations
lstickets on Connection: Ticket operations
lsuseraddresses on Connection: User operations
lsusers on Connection: User operations
Machine: Machine
MailHandler: The MailHandler
mkstaff on Connection: Staff operations
mkticket on Connection: Ticket operations
mkuser on Connection: User operations
MoreThan: Database operations
mvticket on Connection: Ticket operations
Not: Database operations
NotEqual: Database operations
Or: Database operations
quotebody: Message body
receipt on MailHandler: The MailHandler
remoteactions on MailHandler: The MailHandler
replace on Template: TemplateCache.phpi
replace_all on Template: TemplateCache.phpi
replaceheader: Mail headers
resend: Sending mail
returnunknown on MailHandler: The MailHandler
Rlike: Database operations
rmstaff on Connection: Staff operations
rmusers on Connection: User operations
send: Sending mail
Sender: Mail headers
set_transition on Machine: Machine
setticket on Connection: Ticket operations
show on Template: TemplateCache.phpi
shutdown on Machine: Machine
SilentMailHandler: The MailHandler
Subject: Mail headers
thisuser: Utility Functions
To: Mail headers
Transition: Transition
True: Database operations
update on Connection: Ticket operations
XCascabel: Mail headers
allowedstatus: Ticket operations, Basic queue operations, allowedstatus
log: Log operations, log
mailfilters: The MailHandler, Mail support operations, mailfilters
queues: The MailHandler, Basic queue operations, queues
queuestaff: Staff operations, staff and queuestaff
staff: Staff operations, staff and queuestaff
synonyms: Log operations, Ticket operations, synonyms
ticket: Ticket operations, ticket
users: User operations, Ticket operations, users