summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohnathan Rabkin <yonirabkin@member.fsf.org>2013-12-13 15:14:45 -0500
committerJohnathan Rabkin <yonirabkin@member.fsf.org>2013-12-13 15:14:45 -0500
commit5de9af64f18301ca1943ed1e362255f050424fcd (patch)
treead35d76fe74696d092dba59b1d30f40ce95ab7a8
import for initial Savannah tree
-rw-r--r--COPYING339
-rw-r--r--COPYINGv3674
-rw-r--r--doc/Makefile10
-rw-r--r--doc/fdl.texi451
-rw-r--r--doc/gpl.texi725
-rw-r--r--doc/rt-liberation.texinfo1006
-rw-r--r--etc/logo/rt-liberation-logo.svg126
-rw-r--r--etc/rt-dot-el-design60
-rw-r--r--rt-liberation-gnus.el230
-rw-r--r--rt-liberation-multi.el113
-rw-r--r--rt-liberation-storage.el110
-rw-r--r--rt-liberation-update.el106
-rw-r--r--rt-liberation.el1276
13 files changed, 5226 insertions, 0 deletions
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..d511905
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 of the License, 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.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/COPYINGv3 b/COPYINGv3
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/COPYINGv3
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 3 of the License, 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.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/doc/Makefile b/doc/Makefile
new file mode 100644
index 0000000..dd20ede
--- /dev/null
+++ b/doc/Makefile
@@ -0,0 +1,10 @@
+# Don't delete if make is interrupted
+.PRECIOUS: %.info %.html
+
+all: rt-liberation.info
+
+%.info: %.texinfo
+ makeinfo --no-split $<
+
+%.html: %.texinfo
+ makeinfo --html --no-split $<
diff --git a/doc/fdl.texi b/doc/fdl.texi
new file mode 100644
index 0000000..1276677
--- /dev/null
+++ b/doc/fdl.texi
@@ -0,0 +1,451 @@
+@node The GNU FDL, Concept Index, Copying, Top
+@chapter GNU Free Documentation License
+
+@cindex FDL, GNU Free Documentation License
+@center Version 1.2, November 2002
+
+@display
+Copyright @copyright{} 2000,2001,2002 Free Software Foundation, Inc.
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+@end display
+
+@enumerate 0
+@item
+PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document @dfn{free} in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of ``copyleft'', which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+@item
+APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The ``Document'', below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as ``you''. You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A ``Modified Version'' of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A ``Secondary Section'' is a named appendix or a front-matter section
+of the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject. (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The ``Invariant Sections'' are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The ``Cover Texts'' are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A ``Transparent'' copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not ``Transparent'' is called ``Opaque''.
+
+Examples of suitable formats for Transparent copies include plain
+@sc{ascii} without markup, Texinfo input format, La@TeX{} input
+format, @acronym{SGML} or @acronym{XML} using a publicly available
+@acronym{DTD}, and standard-conforming simple @acronym{HTML},
+PostScript or @acronym{PDF} designed for human modification. Examples
+of transparent image formats include @acronym{PNG}, @acronym{XCF} and
+@acronym{JPG}. Opaque formats include proprietary formats that can be
+read and edited only by proprietary word processors, @acronym{SGML} or
+@acronym{XML} for which the @acronym{DTD} and/or processing tools are
+not generally available, and the machine-generated @acronym{HTML},
+PostScript or @acronym{PDF} produced by some word processors for
+output purposes only.
+
+The ``Title Page'' means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, ``Title Page'' means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+A section ``Entitled XYZ'' means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as ``Acknowledgements'',
+``Dedications'', ``Endorsements'', or ``History''.) To ``Preserve the Title''
+of such a section when you modify the Document means that it remains a
+section ``Entitled XYZ'' according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+@item
+VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no other
+conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+@item
+COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to give
+them a chance to provide you with an updated version of the Document.
+
+@item
+MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+@enumerate A
+@item
+Use in the Title Page (and on the covers, if any) a title distinct
+from that of the Document, and from those of previous versions
+(which should, if there were any, be listed in the History section
+of the Document). You may use the same title as a previous version
+if the original publisher of that version gives permission.
+
+@item
+List on the Title Page, as authors, one or more persons or entities
+responsible for authorship of the modifications in the Modified
+Version, together with at least five of the principal authors of the
+Document (all of its principal authors, if it has fewer than five),
+unless they release you from this requirement.
+
+@item
+State on the Title page the name of the publisher of the
+Modified Version, as the publisher.
+
+@item
+Preserve all the copyright notices of the Document.
+
+@item
+Add an appropriate copyright notice for your modifications
+adjacent to the other copyright notices.
+
+@item
+Include, immediately after the copyright notices, a license notice
+giving the public permission to use the Modified Version under the
+terms of this License, in the form shown in the Addendum below.
+
+@item
+Preserve in that license notice the full lists of Invariant Sections
+and required Cover Texts given in the Document's license notice.
+
+@item
+Include an unaltered copy of this License.
+
+@item
+Preserve the section Entitled ``History'', Preserve its Title, and add
+to it an item stating at least the title, year, new authors, and
+publisher of the Modified Version as given on the Title Page. If
+there is no section Entitled ``History'' in the Document, create one
+stating the title, year, authors, and publisher of the Document as
+given on its Title Page, then add an item describing the Modified
+Version as stated in the previous sentence.
+
+@item
+Preserve the network location, if any, given in the Document for
+public access to a Transparent copy of the Document, and likewise
+the network locations given in the Document for previous versions
+it was based on. These may be placed in the ``History'' section.
+You may omit a network location for a work that was published at
+least four years before the Document itself, or if the original
+publisher of the version it refers to gives permission.
+
+@item
+For any section Entitled ``Acknowledgements'' or ``Dedications'', Preserve
+the Title of the section, and preserve in the section all the
+substance and tone of each of the contributor acknowledgements and/or
+dedications given therein.
+
+@item
+Preserve all the Invariant Sections of the Document,
+unaltered in their text and in their titles. Section numbers
+or the equivalent are not considered part of the section titles.
+
+@item
+Delete any section Entitled ``Endorsements''. Such a section
+may not be included in the Modified Version.
+
+@item
+Do not retitle any existing section to be Entitled ``Endorsements'' or
+to conflict in title with any Invariant Section.
+
+@item
+Preserve any Warranty Disclaimers.
+@end enumerate
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled ``Endorsements'', provided it contains
+nothing but endorsements of your Modified Version by various
+parties---for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+@item
+COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled ``History''
+in the various original documents, forming one section Entitled
+``History''; likewise combine any sections Entitled ``Acknowledgements'',
+and any sections Entitled ``Dedications''. You must delete all
+sections Entitled ``Endorsements.''
+
+@item
+COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other documents
+released under this License, and replace the individual copies of this
+License in the various documents with a single copy that is included in
+the collection, provided that you follow the rules of this License for
+verbatim copying of each of the documents in all other respects.
+
+You may extract a single document from such a collection, and distribute
+it individually under this License, provided you insert a copy of this
+License into the extracted document, and follow this License in all
+other respects regarding verbatim copying of that document.
+
+@item
+AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an ``aggregate'' if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+@item
+TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled ``Acknowledgements'',
+``Dedications'', or ``History'', the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+@item
+TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document except
+as expressly provided for under this License. Any other attempt to
+copy, modify, sublicense or distribute the Document is void, and will
+automatically terminate your rights under this License. However,
+parties who have received copies, or rights, from you under this
+License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+@item
+FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions
+of the GNU Free Documentation License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns. See
+@uref{http://www.gnu.org/copyleft/}.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License ``or any later version'' applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation.
+@end enumerate
+
+@page
+@section ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+@smallexample
+@group
+ Copyright (C) @var{year} @var{your name}.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.2
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+ Texts. A copy of the license is included in the section entitled ``GNU
+ Free Documentation License''.
+@end group
+@end smallexample
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the ``with...Texts.'' line with this:
+
+@smallexample
+@group
+ with the Invariant Sections being @var{list their titles}, with
+ the Front-Cover Texts being @var{list}, and with the Back-Cover Texts
+ being @var{list}.
+@end group
+@end smallexample
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
+
+@c Local Variables:
+@c ispell-local-pdict: "ispell-dict"
+@c End:
+
diff --git a/doc/gpl.texi b/doc/gpl.texi
new file mode 100644
index 0000000..978c40d
--- /dev/null
+++ b/doc/gpl.texi
@@ -0,0 +1,725 @@
+@node Copying, The GNU FDL, Local Storage, Top
+
+@unnumbered GNU General Public License
+@center Version 3, 29 June 2007
+
+@c This file is intended to be included in another file.
+
+@display
+Copyright @copyright{} 2007 Free Software Foundation, Inc. @url{http://fsf.org/}
+
+Everyone is permitted to copy and distribute verbatim copies of this
+license document, but changing it is not allowed.
+@end display
+
+@unnumberedsec Preamble
+
+The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom
+to share and change all versions of a program--to make sure it remains
+free software for all its users. We, the Free Software Foundation,
+use the GNU General Public License for most of our software; it
+applies also to any other work released this way by its authors. You
+can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you
+have certain responsibilities if you distribute copies of the
+software, or if you modify it: responsibilities to respect the freedom
+of others.
+
+For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too,
+receive or can get the source code. And you must show them these
+terms so they know their rights.
+
+Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the
+manufacturer can do so. This is fundamentally incompatible with the
+aim of protecting users' freedom to change the software. The
+systematic pattern of such abuse occurs in the area of products for
+individuals to use, which is precisely where it is most unacceptable.
+Therefore, we have designed this version of the GPL to prohibit the
+practice for those products. If such problems arise substantially in
+other domains, we stand ready to extend this provision to those
+domains in future versions of the GPL, as needed to protect the
+freedom of users.
+
+Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish
+to avoid the special danger that patents applied to a free program
+could make it effectively proprietary. To prevent this, the GPL
+assures that patents cannot be used to render the program non-free.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+@iftex
+@unnumberedsec TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center TERMS AND CONDITIONS
+@end ifinfo
+
+@enumerate 0
+@item Definitions.
+
+``This License'' refers to version 3 of the GNU General Public License.
+
+``Copyright'' also means copyright-like laws that apply to other kinds
+of works, such as semiconductor masks.
+
+``The Program'' refers to any copyrightable work licensed under this
+License. Each licensee is addressed as ``you''. ``Licensees'' and
+``recipients'' may be individuals or organizations.
+
+To ``modify'' a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of
+an exact copy. The resulting work is called a ``modified version'' of
+the earlier work or a work ``based on'' the earlier work.
+
+A ``covered work'' means either the unmodified Program or a work based
+on the Program.
+
+To ``propagate'' a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+To ``convey'' a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user
+through a computer network, with no transfer of a copy, is not
+conveying.
+
+An interactive user interface displays ``Appropriate Legal Notices'' to
+the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+@item Source Code.
+
+The ``source code'' for a work means the preferred form of the work for
+making modifications to it. ``Object code'' means any non-source form
+of a work.
+
+A ``Standard Interface'' means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+The ``System Libraries'' of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+``Major Component'', in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+The ``Corresponding Source'' for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+The Corresponding Source need not include anything that users can
+regenerate automatically from other parts of the Corresponding Source.
+
+The Corresponding Source for a work in source code form is that same
+work.
+
+@item Basic Permissions.
+
+All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+You may make, run and propagate covered works that you do not convey,
+without conditions so long as your license otherwise remains in force.
+You may convey covered works to others for the sole purpose of having
+them make modifications exclusively for you, or provide you with
+facilities for running those works, provided that you comply with the
+terms of this License in conveying all material for which you do not
+control copyright. Those thus making or running the covered works for
+you must do so exclusively on your behalf, under your direction and
+control, on terms that prohibit them from making any copies of your
+copyrighted material outside their relationship with you.
+
+Conveying under any other circumstances is permitted solely under the
+conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+@item Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such
+circumvention is effected by exercising rights under this License with
+respect to the covered work, and you disclaim any intention to limit
+operation or modification of the work as a means of enforcing, against
+the work's users, your or third parties' legal rights to forbid
+circumvention of technological measures.
+
+@item Conveying Verbatim Copies.
+
+You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+@item Conveying Modified Source Versions.
+
+You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these
+conditions:
+
+@enumerate a
+@item
+The work must carry prominent notices stating that you modified it,
+and giving a relevant date.
+
+@item
+The work must carry prominent notices stating that it is released
+under this License and any conditions added under section 7. This
+requirement modifies the requirement in section 4 to ``keep intact all
+notices''.
+
+@item
+You must license the entire work, as a whole, under this License to
+anyone who comes into possession of a copy. This License will
+therefore apply, along with any applicable section 7 additional terms,
+to the whole of the work, and all its parts, regardless of how they
+are packaged. This License gives no permission to license the work in
+any other way, but it does not invalidate such permission if you have
+separately received it.
+
+@item
+If the work has interactive user interfaces, each must display
+Appropriate Legal Notices; however, if the Program has interactive
+interfaces that do not display Appropriate Legal Notices, your work
+need not make them do so.
+@end enumerate
+
+A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+``aggregate'' if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+@item Conveying Non-Source Forms.
+
+You may convey a covered work in object code form under the terms of
+sections 4 and 5, provided that you also convey the machine-readable
+Corresponding Source under the terms of this License, in one of these
+ways:
+
+@enumerate a
+@item
+Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by the
+Corresponding Source fixed on a durable physical medium customarily
+used for software interchange.
+
+@item
+Convey the object code in, or embodied in, a physical product
+(including a physical distribution medium), accompanied by a written
+offer, valid for at least three years and valid for as long as you
+offer spare parts or customer support for that product model, to give
+anyone who possesses the object code either (1) a copy of the
+Corresponding Source for all the software in the product that is
+covered by this License, on a durable physical medium customarily used
+for software interchange, for a price no more than your reasonable
+cost of physically performing this conveying of source, or (2) access
+to copy the Corresponding Source from a network server at no charge.
+
+@item
+Convey individual copies of the object code with a copy of the written
+offer to provide the Corresponding Source. This alternative is
+allowed only occasionally and noncommercially, and only if you
+received the object code with such an offer, in accord with subsection
+6b.
+
+@item
+Convey the object code by offering access from a designated place
+(gratis or for a charge), and offer equivalent access to the
+Corresponding Source in the same way through the same place at no
+further charge. You need not require recipients to copy the
+Corresponding Source along with the object code. If the place to copy
+the object code is a network server, the Corresponding Source may be
+on a different server (operated by you or a third party) that supports
+equivalent copying facilities, provided you maintain clear directions
+next to the object code saying where to find the Corresponding Source.
+Regardless of what server hosts the Corresponding Source, you remain
+obligated to ensure that it is available for as long as needed to
+satisfy these requirements.
+
+@item
+Convey the object code using peer-to-peer transmission, provided you
+inform other peers where the object code and Corresponding Source of
+the work are being offered to the general public at no charge under
+subsection 6d.
+
+@end enumerate
+
+A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+A ``User Product'' is either (1) a ``consumer product'', which means any
+tangible personal property which is normally used for personal,
+family, or household purposes, or (2) anything designed or sold for
+incorporation into a dwelling. In determining whether a product is a
+consumer product, doubtful cases shall be resolved in favor of
+coverage. For a particular product received by a particular user,
+``normally used'' refers to a typical or common use of that class of
+product, regardless of the status of the particular user or of the way
+in which the particular user actually uses, or expects or is expected
+to use, the product. A product is a consumer product regardless of
+whether the product has substantial commercial, industrial or
+non-consumer uses, unless such uses represent the only significant
+mode of use of the product.
+
+``Installation Information'' for a User Product means any methods,
+procedures, authorization keys, or other information required to
+install and execute modified versions of a covered work in that User
+Product from a modified version of its Corresponding Source. The
+information must suffice to ensure that the continued functioning of
+the modified object code is in no case prevented or interfered with
+solely because modification has been made.
+
+If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or
+updates for a work that has been modified or installed by the
+recipient, or for the User Product in which it has been modified or
+installed. Access to a network may be denied when the modification
+itself materially and adversely affects the operation of the network
+or violates the rules and protocols for communication across the
+network.
+
+Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+@item Additional Terms.
+
+``Additional permissions'' are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders
+of that material) supplement the terms of this License with terms:
+
+@enumerate a
+@item
+Disclaiming warranty or limiting liability differently from the terms
+of sections 15 and 16 of this License; or
+
+@item
+Requiring preservation of specified reasonable legal notices or author
+attributions in that material or in the Appropriate Legal Notices
+displayed by works containing it; or
+
+@item
+Prohibiting misrepresentation of the origin of that material, or
+requiring that modified versions of such material be marked in
+reasonable ways as different from the original version; or
+
+@item
+Limiting the use for publicity purposes of names of licensors or
+authors of the material; or
+
+@item
+Declining to grant rights under trademark law for use of some trade
+names, trademarks, or service marks; or
+
+@item
+Requiring indemnification of licensors and authors of that material by
+anyone who conveys the material (or modified versions of it) with
+contractual assumptions of liability to the recipient, for any
+liability that these contractual assumptions directly impose on those
+licensors and authors.
+@end enumerate
+
+All other non-permissive additional terms are considered ``further
+restrictions'' within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions; the
+above requirements apply either way.
+
+@item Termination.
+
+You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+@item Acceptance Not Required for Having Copies.
+
+You are not required to accept this License in order to receive or run
+a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+@item Automatic Licensing of Downstream Recipients.
+
+Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+An ``entity transaction'' is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+@item Patents.
+
+A ``contributor'' is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's ``contributor version''.
+
+A contributor's ``essential patent claims'' are all patent claims owned
+or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, ``control'' includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+In the following three paragraphs, a ``patent license'' is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To ``grant'' such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. ``Knowingly relying'' means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+A patent license is ``discriminatory'' if it does not include within the
+scope of its coverage, prohibits the exercise of, or is conditioned on
+the non-exercise of one or more of the rights that are specifically
+granted under this License. You may not convey a covered work if you
+are a party to an arrangement with a third party that is in the
+business of distributing software, under which you make payment to the
+third party based on the extent of your activity of conveying the
+work, and under which the third party grants, to any of the parties
+who would receive the covered work from you, a discriminatory patent
+license (a) in connection with copies of the covered work conveyed by
+you (or copies made from those copies), or (b) primarily for and in
+connection with specific products or compilations that contain the
+covered work, unless you entered into that arrangement, or that patent
+license was granted, prior to 28 March 2007.
+
+Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+@item No Surrender of Others' Freedom.
+
+If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey
+a covered work so as to satisfy simultaneously your obligations under
+this License and any other pertinent obligations, then as a
+consequence you may not convey it at all. For example, if you agree
+to terms that obligate you to collect a royalty for further conveying
+from those to whom you convey the Program, the only way you could
+satisfy both those terms and this License would be to refrain entirely
+from conveying the Program.
+
+@item Use with the GNU Affero General Public License.
+
+Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+@item Revised Versions of this License.
+
+The Free Software Foundation may publish revised and/or new versions
+of the GNU General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies that a certain numbered version of the GNU General Public
+License ``or any later version'' applies to it, you have the option of
+following the terms and conditions either of that numbered version or
+of any later version published by the Free Software Foundation. If
+the Program does not specify a version number of the GNU General
+Public License, you may choose any version ever published by the Free
+Software Foundation.
+
+If the Program specifies that a proxy can decide which future versions
+of the GNU General Public License can be used, that proxy's public
+statement of acceptance of a version permanently authorizes you to
+choose that version for the Program.
+
+Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+@item Disclaimer of Warranty.
+
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM ``AS IS'' WITHOUT
+WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND
+PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE
+DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR
+CORRECTION.
+
+@item Limitation of Liability.
+
+IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR
+CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
+ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT
+NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR
+LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM
+TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER
+PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+@item Interpretation of Sections 15 and 16.
+
+If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+@iftex
+@heading END OF TERMS AND CONDITIONS
+@end iftex
+@ifinfo
+@center END OF TERMS AND CONDITIONS
+@end ifinfo
+@unnumberedsec How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these
+terms.
+
+To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the ``copyright'' line and a pointer to where the full notice is found.
+@smallexample
+@var{one line to give the program's name and a brief idea of what it does.}
+Copyright (C) @var{year} @var{name of author}
+
+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 3 of the License, 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.
+
+You should have received a copy of the GNU General Public License
+along with this program. If not, see @url{http://www.gnu.org/licenses/}.
+@end smallexample
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+@smallexample
+@var{program} Copyright (C) @var{year} @var{name of author}
+This program comes with ABSOLUTELY NO WARRANTY; for details type @samp{show w}.
+This is free software, and you are welcome to redistribute it under certain conditions; type @samp{show c} for details.
+@end smallexample
+
+The hypothetical commands @samp{show w} and @samp{show c} should show
+the appropriate parts of the General Public License. Of course, your
+program's commands might be different; for a GUI interface, you would
+use an ``about box''.
+
+You should also get your employer (if you work as a programmer) or school,
+if any, to sign a ``copyright disclaimer'' for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+@url{http://www.gnu.org/licenses/}.
+
+The GNU General Public License does not permit incorporating your
+program into proprietary programs. If your program is a subroutine
+library, you may consider it more useful to permit linking proprietary
+applications with the library. If this is what you want to do, use
+the GNU Lesser General Public License instead of this License. But
+first, please read @url{http://www.gnu.org/philosophy/why-not-lgpl.html}.
+
+@end enumerate
diff --git a/doc/rt-liberation.texinfo b/doc/rt-liberation.texinfo
new file mode 100644
index 0000000..59af59a
--- /dev/null
+++ b/doc/rt-liberation.texinfo
@@ -0,0 +1,1006 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename rt-liberation.info
+@settitle The rt-liberation Manual
+@c %**end of header
+
+@c History: This manual was started on the 6th of April 2009.
+
+@dircategory Emacs
+@direntry
+* rt-liberation: (rt-liber). rt-liberation
+@end direntry
+
+
+@copying
+ @copyright{} 2009
+ Yoni Rabkin yonirabkin@@member.fsf.org
+@quotation
+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, no Front-Cover Texts, and no Back-Cover Texts. A
+copy of the license is included in the section entitled ``GNU Free
+Documentation License''.
+@end quotation
+@end copying
+
+
+@c For printed material
+@titlepage
+@title The rt-liberation Manual
+@page
+@vskip 0pt plus 1filll
+@insertcopying
+@end titlepage
+@contents
+@c END For printed material
+
+
+@ifnottex
+@node Top, Introduction, (dir), (dir)
+@top The rt-liberation Manual
+
+This is the Manual for the rt-liberation system
+
+@insertcopying
+
+@menu
+* Introduction:: Introduction to rt-liberation.
+* Dependencies:: Before you can use rt-liberation.
+* Installation:: Setup rt-liberation to work on the system.
+
+Using rt-liberation
+* Queries:: Retrieve particular tickets from the server.
+* Ticket Browser:: Browse the query results.
+* Ticket Viewer:: Interface to query results.
+
+Extensions
+* Gnus Integration:: Sending email to the RT server via Gnus.
+* Tracking Updates:: Keeping up to date with ticket changes.
+* Batch Operations:: Performing operations on batches of tickets.
+* Local Storage:: Associate arbitrary data with tickets.
+
+Copying and license
+* Copying:: The GNU General Public License gives you
+ permission to redistribute rt-liberation
+ on certain terms; it also explains that
+ there is no warranty.
+
+* The GNU FDL:: The license for this documentation.
+
+Indices
+* Concept Index::
+* Function Index::
+* Variable Index::
+* Keybinding Index::
+
+@detailmenu
+ --- The Detailed Node Listing ---
+
+Queries
+
+* Query Compiler:: Compiling Emacs Lisp to TicketSQL.
+* Query Language:: A description of the Sexp-based language.
+
+Ticket Browser
+
+* Ticket Browser Display:: How tickets are displayed in the browser.
+* Ticket Browser Sorting:: How tickets are sorted in the browser.
+* Ticket Browser Filtering:: How to filter tickets out of the browser.
+* Mutliple Ticket Browsers:: More than one ticket browser buffer.
+
+@end detailmenu
+@end menu
+
+@end ifnottex
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Introduction
+@chapter Introduction
+
+@cindex introduction
+
+rt-liberation is a GNU/Emacs package for working with the Request
+Tracker (henceforth abbreviated as just ``RT'') software from Best
+Practical Solutions. RT has a Web interface and a command line
+interface (the ``RT CLI''). rt-liberation uses the RT CLI as a backend
+to communicate to the server.
+
+rt-liberation allows sending search queries to the RT server, browsing
+the resulting tickets, viewing the tickets' contents and performing
+operations on the ticket.
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Dependencies
+@chapter Dependencies
+
+@cindex dependencies
+
+rt-liberation has been tested exclusively on GNU/Emacs, with very
+recent versions.
+
+Since rt-liberation uses the command line interface as a backend to
+communicate with the RT server it will need a local copy of the RT
+software on the machine running rt-liberation. RT is available at
+@uref{http://bestpractical.com/rt/download.html}
+
+At the time of writing the recommended version of RT to use as a
+backend for rt-liberation is 3.8.2. Version 3.8.2 will provide
+shorter response times and less calls out to the server.
+
+Please check that the RT CLI runs from the shell and can communicate
+with the server in question. If that doesn't work neither will
+rt-liberation.
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Installation
+@chapter Installation
+
+@cindex installation
+
+rt-liberation can be configured in the ~/.emacs file.
+
+Place rt-liberation in the load path:
+
+@lisp
+(add-to-list 'load-path "/PATH/TO/rt-liberation/")
+@end lisp
+
+Tell GNU/Emacs to load the package with:
+
+@lisp
+(require 'rt-liberation)
+@end lisp
+
+Tell rt-liberation where to find the RT binary and which version is
+being used, for example:
+
+@lisp
+(setq rt-liber-rt-binary "~/src/rt-3.8.2/bin/rt"
+ rt-liber-rt-version "3.8.8")
+@end lisp
+
+rt-liberation can issue a command to ``take'' a ticket, that is,
+assign it to yourself. For this the variable @var{rt-liber-username}
+must be set:
+
+@lisp
+(setq rt-liber-username "someuser")
+@end lisp
+
+rt-liberation can also launch a Web browser to visit a ticket. For
+that to work the base URL needs to be set in
+@var{rt-liber-base-url}. For example:
+
+(setq rt-liber-base-url "https://rt.foo.org/")
+
+@c --------------------------------------------------
+
+@node Queries
+@chapter Queries
+
+@cindex queries
+
+A typical RT server is meant to manage a large amount of tickets. Much
+more that would be convenient to view all at once. Instead queries are
+used to view only a subset of the tickets on the server.
+
+rt-liberation has its own Sexp-based query language which maps to RT's
+TicketSQL language.
+
+@menu
+* Query Compiler:: Compiling Emacs Lisp to TicketSQL.
+* Query Language:: A description of the Sexp-based language.
+@end menu
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Query Compiler
+@section Query Compiler
+
+@cindex query compiler
+
+In order to browse and view tickets a list of needs to be requested
+from the RT server. Typically the tickets answer some kind of
+criteria, for example ``tickets no older than a week owned by me which
+have \``foobar\'' in their subject line''. In RT these criteria are
+formulated with ``TicketSQL'' queries; a structured query language
+specific to RT.
+
+rt-liberation provides a query compiler function to compile Emacs Lisp
+symbolic expressions into TicketSQL. The query compiler supports a
+number of TicketSQL tokens.
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Query Language
+@section Query Language
+
+@cindex query language
+
+rt-liberation's Sexp-based query language covers a portion of the
+TicketSQL language. Here are some of the supported TicketSQL tokens:
+Boolean tokens as a means of combining query subsections: ``and'', ``or'',
+``not''. LIKE attribute tokens: ``subject'', ``content''.
+
+For example here is a query with both Boolean and LIKE tokens:
+
+@lisp
+(rt-liber-compile-query
+ (and (queue "bugs")
+ (content "gnu")))
+
+==> "Queue = 'bugs' AND Content LIKE 'gnu'"
+@end lisp
+
+We can also express negation (note that the compiler produces "!=" and
+"NOT LIKE" for negation depending on the context):
+
+@lisp
+(rt-liber-compile-query
+ (and (queue "bugs")
+ (not (owner "Nobody"))
+ (not (content "sprigz"))
+ (status "new")))
+
+==> "Queue = 'licensing' AND Owner != 'Nobody' \
+ AND Content NOT LIKE 'sprigz' AND Status = 'new'"
+@end lisp
+
+Attribute tokens which match an attribute to a specific field such as:
+``owner'', ``status'' and ``queue''. Temporal tokens which limit the search
+results to tickets within a certain time interval: ``created'' and
+``lastupdated''. Note that temporal keywords such as ``created'' always
+accept two arguments: BEFORE and AFTER. When either BEFORE or AFTER
+aren't needed, use NIL instead.
+
+One of the advantages of being able to express the TicketSQL queries
+as Emacs Lisp is to be able to express queries using Emacs Lisp
+functions.
+
+Here is a slightly more involved example to illustrate:
+
+@lisp
+(rt-liber-compile-query
+ (and (queue "bugs")
+ (owner "me@@myaddress.com")
+ (status "open")
+ (lastupdated nil
+ (format-time-string
+ "%Y-%m-%d"
+ (seconds-to-time
+ (- (time-to-seconds (current-time))
+ (* 60 60 24 7)))))))
+
+==> "Queue = 'bugs' AND Owner = 'me@@myaddress.com' AND Status = 'open' AND LastUpdated > '2009-03-30'"
+@end lisp
+
+
+Here is an example of how the ticket browser and compiler can be used
+in function calls:
+
+@lisp
+(defun rt-liber-display-ticket (ticket-id)
+ "Display ticket with TICKET-ID in the ticket-browser."
+ (interactive "MTicket ID: ")
+ (rt-liber-browse-query
+ (rt-liber-compile-query
+ (and (queue "complaints")
+ (id ticket-id)))))
+@end lisp
+
+
+
+
+@c --------------------------------------------------
+
+@node Ticket Browser
+@chapter Ticket Browser
+
+@cindex ticket browser
+
+The ticket browser is a special buffer which provides a convenient
+interface to the results of a server query. The ticket browser can be
+started by invoking: (rt-liber-browse-query QUERY), where QUERY is a
+TicketSQL query. The TicketSQL query can be entered manually as a
+string or as the return value of the query compiler.
+
+@deffn Function rt-liber-browse-query QUERY &optional NEW
+Runs QUERY against the server and launches the browser.
+
+If NEW is non-nil then the query results will be displayed in a new
+buffer, otherwise the query results will override the contents of the
+existing ticket browser buffer. If NEW is a string then that will be
+the name of the new buffer.
+@end deffn
+
+The TicketSQL query can be the return value of the query compiler. For
+example:
+
+@lisp
+(rt-liber-browse-query
+ (rt-liber-compile-query
+ (and (queue "bugs")
+ (content "gnu")))
+@end lisp
+
+
+Sine the return value of the query compiler is just a TicketSQL
+string, the following is equivalent:
+
+@lisp
+(rt-liber-browse-query "Queue = 'bugs' AND Content LIKE 'gnu'")
+@end lisp
+
+The ticket browser defines a number of commands:
+
+@table @kbd
+@item q
+@kindex q (ticket browser)
+@findex rt-liber-browser-mode-quit
+Bury the ticket browser buffer.
+
+@item n
+@kindex n (ticket browser)
+@findex rt-liber-next-ticket-in-browser
+Move point to the next ticket.
+
+@item p
+@kindex p (ticket browser)
+@findex rt-liber-previous-ticket-in-browser
+Move point to the previous ticket.
+
+@item RET
+@kindex RET (ticket browser)
+@findex rt-liber-display-ticket-at-point
+Visit the ticket at point in the @xref{Ticket Viewer}.
+
+@item g
+@kindex g (ticket browser)
+@findex revert-buffer
+Refresh the contents of the browser buffer.
+
+@item G
+@kindex G (ticket browser)
+@findex rt-liber-browser-refresh-and-return
+Refresh the contents of the browser buffer. Return point to the
+current ticket after the refresh (if possible).
+
+@item s
+@kindex s (ticket browser)
+@findex rt-liber-browser-mark-as-spam
+Mark the ticket as spam.
+
+@item S
+@kindex S (ticket browser)
+@findex rt-liber-multi-delete-spam
+Delete marked tickets as spam (requires rt-liberation-multi package).
+
+@item a
+@kindex a (ticket browser)
+@findex rt-liber-browser-assign
+Assign the ticket to a user.
+
+@item r
+@kindex r (ticket browser)
+@findex rt-liber-browser-resolve
+Mark the ticket as ``resolved''.
+
+@item o
+@kindex o (ticket browser)
+@findex rt-liber-browser-open
+Mark the ticket as ``open''.
+
+@item t
+@kindex t (ticket browser)
+@findex rt-liber-browser-take-ticket-at-point
+Assign the ticket at point to @var{rt-liber-username}.
+
+@item SPC
+@kindex SPC (ticket browser)
+@findex scroll-up
+Scroll the text of the ticket browser upward.
+
+@item DEL
+@kindex DEL (ticket browser)
+@findex scroll-down
+Scroll the text of the ticket browser downward.
+
+@item m
+@kindex m (ticket browser)
+@findex rt-liber-browser-move
+Move the ticket to a different queue.
+
+@end table
+
+@menu
+* Ticket Browser Display:: How tickets are displayed in the browser.
+* Ticket Browser Sorting:: How tickets are sorted in the browser.
+* Ticket Browser Filtering:: How to filter tickets out of the browser.
+* Mutliple Ticket Browsers:: More than one ticket browser buffer.
+@end menu
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Ticket Browser Display
+@section Ticket Browser Display
+
+@cindex ticket browser display function
+
+The ticket browser displays the tickets in the browser by calling
+@dfn{rt-liber-ticketlist-browser-redraw-f} which can be changed and
+customized. Any implementation of
+@dfn{rt-liber-ticketlist-browser-redraw-f} must leave point at the end
+of the ticket text.
+
+The ticket data itself can be displayed using rt-liberation ticket
+format string %-sequences:
+
+@table @asis
+@item %i
+ID number of the ticket in the RT database.
+@item %s
+Subject line.
+@item %c
+Ticket creation time.
+@item %S
+Ticket status (``open'', ``new'' etc.)
+@item %r
+Whether the ticket is resolved.
+@item %R
+Requestor/s
+@item %C
+Creator of the ticket.
+@item %o
+Owner of the ticket.
+@item %q
+The queue originating the ticket.
+@end table
+
+Here is an example implementation of
+@dfn{rt-liber-ticketlist-browser-redraw-f} showing the use of the
+%-sequences. Note the use of text properties to add color to ticket
+text. The use of text properties as opposed to font-locking is meant
+to ease customization because otherwise any change in ticket display
+would break the font-locking regular expressions.
+
+@lisp
+(defun rt-liber-ticketlist-browser-redraw-f (ticket)
+ "Display TICKET."
+ (insert (rt-liber-format "[%c] %i" ticket))
+ (add-text-properties (point-at-bol)
+ (point-at-eol)
+ '(face rt-liber-ticket-face))
+ (newline)
+ (insert (rt-liber-format " [%S] %s" ticket))
+ (newline)
+ (insert (rt-liber-format " %o <== %R" ticket)))
+@end lisp
+
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Ticket Browser Sorting
+@section Ticket Browser Sorting
+
+@cindex ticket browser sorting
+
+The tickets in the browser are displayed by default in reverse
+chronological order. Ticket sorting is done by a call to
+@dfn{rt-liber-browser-default-sorting-function}.
+
+Other sorting orders can be used by binding
+@dfn{rt-liber-browser-default-sorting-function} to a different
+function. To ease writing such functions rt-liberation provides two
+predicate functions to perform comparisons between ticket objects:
+
+@defun rt-liber-lex-lessthan-p a b field
+Return true if A is lexicographically less than B in FIELD.
+
+Here is an example of sorting tickets lexicographically by owner name
+using @dfn{rt-liber-lex-lessthan-p} (note that you can feed
+@dfn{rt-liber-lex-lessthan-p} a date/time string and it will sort it
+just fine except that it wouldn't make any sense):
+
+@lisp
+(defun rt-liber-sort-by-owner (ticket-list)
+ "Sort TICKET-LIST lexicographically by owner."
+ (rt-liber-sort-ticket-list
+ ticket-list
+ #'(lambda (a b)
+ (rt-liber-lex-lessthan-p a b "Owner"))))
+@end lisp
+
+@end defun
+
+@defun rt-liber-time-lessthan-p a b field
+Return t if A is chronologically less than B in FIELD.
+
+Here is an example of sorting tickets lexicographically by owner name
+using @dfn{rt-liber-time-lessthan-p} (note that feeding
+@dfn{rt-liber-time-lessthan-p} anything but a date/time string, in
+this case ``Created'' contains a date, will result in an error being
+signaled).
+
+@lisp
+(defun rt-liber-sort-by-time-created (ticket-list)
+ "Sort TICKET-LIST in reverse chronological order."
+ (reverse
+ (rt-liber-sort-ticket-list
+ ticket-list
+ #'(lambda (a b)
+ (rt-liber-time-lessthan-p a b "Created")))))
+@end lisp
+
+@end defun
+
+@c -------------------------------------------------------------------
+
+@node Ticket Browser Filtering
+@section Ticket Browser Filtering
+
+@cindex ticket browser filtering filter
+
+The Ticket Browser can also filter out (that is, not display) certain
+tickets based on particular criteria. This probably shouldn't be used
+instead of a properly formed RT query, but when used in conjunction
+with correctly formulated queries it becomes a powerful tool.
+
+During ticket display processing the Ticket Browser will call the
+function pointed to by @var{rt-liber-browser-default-filter-function}
+on each ticket, passing the function the ticket alist as a single
+argument. The function is set by default to
+@dfn{rt-liber-default-filter-f}, which is a function which will
+display all tickets and filter none.
+
+If any tickets are filtered, the Ticket Browser will display the
+filtered ticket count at the bottom ticket listing.
+
+Here is a simple example of how to filter out all of the tickets which
+have a status of ``deleted''.
+
+First we define a custom filter function. Note how it accepts a single
+argument, which is the ticket alist, and returns nil if the ticket is
+to be filtered.
+
+@lisp
+(defun rt-liber-browser-deleted-filter (ticket)
+ (not
+ (and ticket
+ (string= (cdr (assoc "Status" ticket))
+ "deleted"))))
+@end lisp
+
+Then we assign that function to be our default filtering function:
+
+@lisp
+(setq rt-liber-browser-default-filter-function
+ 'rt-liber-browser-deleted-filter)
+@end lisp
+
+@c -------------------------------------------------------------------
+
+
+@node Mutliple Ticket Browsers
+@section Mutliple Ticket Browsers
+
+@cindex ticket browser multiple buffer
+
+It is sometimes useful to rename the ticket browser buffer to
+something more informative than the default
+@var{rt-liber-browser-buffer-name}, especially if there are multiple
+ticket browsers.
+
+Changing a ticket browser's name can be done normally with
+`rename-buffer', but it is also possible to name the ticket browser
+when it is created. In the following example two ticket browser
+buffers will be created displaying the query results and named
+``*updated by supervisor*'' and ``*new tickets*'' respectively:
+
+@lisp
+(defun rt-liber-daily-rounds ()
+ (interactive)
+
+ (rt-liber-browse-query
+ (rt-liber-compile-query
+ (and (queue "complaints")
+ (owner "lem.e.tweakit")
+ (status "open")
+ (lastupdatedby "molly.manager")))
+ "*updated by supervisor*")
+
+ (rt-liber-browse-query
+ (rt-liber-compile-query
+ (and (queue "complaints")
+ (owner "Nobody")
+ (status "new")))
+ "*new tickets*"))
+@end lisp
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Ticket Viewer
+@chapter Ticket Viewer
+
+@cindex ticket viewer
+
+The ticket viewer is an interface for viewing the contents of a
+ticket. It provides font-locking to make reading the contents easier
+via @var{rt-liber-viewer-font-lock-keywords} and a number of
+key-bindings.
+
+The ticket viewer provides key-bindings to help compose emails to send
+to the RT email interface. The key-bindings for composing email
+described below are generic, what actually happens when you invoke
+them depends on the email-backend system you have installed into
+rt-liberation. @file{rt-liberation-gnus.el} provides integrations with
+Gnus, @xref{Gnus Integration}.
+
+Setting @var{rt-liber-jump-to-latest} to `t' will cause the viewer to
+automatically scroll to the latest comment in a ticket when that
+ticket is visited. By default @var{rt-liber-jump-to-latest} is set to
+`nil'.
+
+When in the ticket viewer buffer, invoking
+@dfn{rt-liber-viewer-take-ticket} will ``take'' the ticket.
+
+@table @kbd
+
+@item q
+@kindex q (ticket viewer)
+@findex rt-liber-viewer-mode-quit
+Bury the ticket viewer buffer.
+
+@item n
+@kindex n (ticket viewer)
+@findex rt-liber-next-section-in-viewer
+Move point to the next section in ticket.
+
+@item N
+@kindex N (ticket viewer)
+@findex rt-liber-jump-to-latest-correspondence
+Move point to the newest correspondence section, if any.
+
+@item p
+@kindex p (ticket viewer)
+@findex rt-liber-previous-section-in-viewer
+Move point to the previous section in ticket.
+
+@item V
+@kindex V (ticket viewer)
+@findex rt-liber-viewer-visit-in-browser
+Visit the current ticket in a Web browser.
+
+@item m
+@kindex m (ticket viewer)
+@findex rt-liber-viewer-answer
+Compose an answer to the current ticket.
+
+@item M
+@kindex M (ticket viewer)
+@findex rt-liber-viewer-answer-this
+Compose an answer to the current ticket. The content section around
+point will be inserted into the email body and commented out.
+
+@item t
+@kindex t (ticket viewer)
+@findex rt-liber-viewer-answer-provisionally
+Compose a provisional answer to the current ticket.
+
+@item T
+@kindex t (ticket viewer)
+@findex rt-liber-viewer-answer-provisionally-this
+Compose a provisional answer to the current ticket. The content
+section around point will be inserted into the email body and
+commented out.
+
+@item F
+@kindex F (ticket viewer)
+@findex rt-liber-viewer-answer-verbatim-this
+Compose an answer to the current ticket. The content section around
+point will be inserted into the email body verbatim.
+
+@item c
+@kindex c (ticket viewer)
+@findex rt-liber-viewer-comment
+Compose a comment for the current ticket.
+
+@item C
+@kindex C (ticket viewer)
+@findex rt-liber-viewer-comment-this
+Comment on the ticket using the current context
+
+@item g
+@kindex g (ticket viewer)
+@findex revert-buffer
+Refresh and redisplay the current ticket.
+
+@item SPC
+@kindex SPC (ticket viewer)
+@findex scroll-up
+Scroll text of ticket viewer upward.
+
+@item DEL
+@kindex DEL (ticket viewer)
+@findex scroll-down
+Scroll text of ticket viewer downward.
+
+@item h
+@kindex h (ticket viewer)
+@findex rt-liber-viewer-show-ticket-browser
+Display the associated ticket in the ticket browser.
+
+@end table
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Gnus Integration
+@chapter Gnus Integration
+
+@cindex Gnus Integration
+
+The file @file{rt-liberation-gnus.el} implements integration with Gnus
+for composing emails. To enable the feature, `require' it after
+loading rt-liberation:
+
+@lisp
+(require 'rt-liberation-gnus)
+@end lisp
+
+In order for rt-liberation-gnus to be useful a few variables need to
+be specialized. The following is example code which sets these
+variables followed by a more thorough description of the variables:
+
+@lisp
+(setq rt-liber-gnus-comment-address "our-rtserver-comment@@ourserver.org"
+ rt-liber-gnus-address "our-rtserver@@ourserver.org"
+ rt-liber-gnus-subject-name "ourserver.org"
+ rt-liber-gnus-answer-headers '(("Gcc" . "nnml:Send-Mail")
+ ("X-Ethics" . "Use GNU"))
+ rt-liber-gnus-signature "Kind Regards")
+@end lisp
+
+@defopt
+@var{rt-liber-gnus-address} is the email address which is configured
+in the RT server email interface for sending a response to the
+ticket's requestor.
+@end defopt
+@defopt
+@var{rt-liber-gnus-comment-address} is the email address which is
+configured in the RT server email interface for adding a comment under
+the ticket in question.
+@end defopt
+@defopt
+@var{rt-liber-gnus-subject-name} is a string, typically included at
+the beginning of the square brackets in the subject. The string is a
+part of the subject line which helps the RT server recognize the
+email.
+@end defopt
+@defopt
+@var{rt-liber-gnus-answer-headers} defines a list of dotted-pairs
+containing the header name and value for additional email headers.
+@end defopt
+@defopt
+A signature can be added automatically to the end of the email by
+setting @var{rt-liber-gnus-signature} to be some text. It is useful to
+include newlines in this text to make the signature format nicely.
+@end defopt
+
+Once rt-liberation-gnus is loaded and customized the key-bindings in
+the Viewer will be able to call into it, @xref{Ticket Viewer}.
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Tracking Updates
+@chapter Tracking Updates
+
+@cindex Tracking Updates
+
+The functions in @file{rt-liberation-update.el} help keep up with
+updates to the ticket database. To enable the feature, `require' it
+after loading rt-liberation:
+
+@lisp
+(require 'rt-liberation-update)
+@end lisp
+
+Then set @var{rt-liber-update-default-queue} to be the name of the
+queue to watch for updates. For example:
+
+@lisp
+(setq rt-liber-update-default-queue "complaints")
+@end lisp
+
+@defun rt-liber-update &optional no-update
+@code{rt-liber-update} is an interactive function which runs a query
+against the RT server asking for the tickets which have been updated
+since the time @code{rt-liber-update} was last run (each time it runs,
+it leaves a time-stamp). If no time-stamp is found, for instance when
+you run @code{rt-liber-update} for the first time, today's date is
+used.
+
+With the NO-UPDATE prefix, @code{rt-liber-update} will not update the
+time-stamp so that the next invocation will produce the same result.
+@end defun
+
+
+
+
+@c --------------------------------------------------
+
+@node Batch Operations
+@chapter Batch Operations
+
+@cindex Batch Operations
+
+The extension @file{rt-liberation-multi.el} implements performing
+batch operations on groups of tickets. It works in two stages: First
+mark an arbitrary number of tickets within the same buffer then call a
+batch operation function on them. The batch operation functions work
+the same way as function which work on single tickets only that they
+iterate through all of the marked tickets.
+
+To enable batch operations first load @file{rt-liberation-multi.el}:
+
+@lisp
+(require 'rt-liberation-storage)
+@end lisp
+
+@table @kbd
+@item M
+@kindex M (ticket browser)
+@findex rt-liber-mark-ticket-at-point
+Mark the ticket at point for future action. If the ticket at point is
+already marked then unmark it.
+@end table
+
+@defun rt-liber-multi-set-status-open
+Set the status of all the marked tickets to ``open''.
+@end defun
+
+@defun rt-liber-multi-set-status-resolved
+Set the status of all the marked tickets to ``resolved.
+@end defun
+
+@defun rt-liber-multi-assign name
+Assign all of the marked tickets to NAME.
+@end defun
+
+@defun rt-liber-multi-flag-as-spam-and-delete
+Set the status of all the marked tickets to ``is-spam'' and delete.
+@end defun
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Local Storage
+@chapter Local Storage
+
+@cindex Local Storage
+
+@file{rt-liberation-storage.el} implements associating arbitrary
+ancillary data with tickets. The data is stored locally and is not
+sent to the RT server.
+
+To enable local storage first load @file{rt-liberation-storage.el}:
+
+@lisp
+(require 'rt-liberation-storage)
+@end lisp
+
+Then enable the display of ancillary data with:
+
+@lisp
+(setq rt-liber-anc-p t)
+@end lisp
+
+The associated data is edited and displayed in the ticket browser with
+the following command key:
+
+@table @kbd
+@item A
+@kindex A (ticket browser)
+@findex rt-liber-browser-ancillary-text
+Associate text with the ticket at point. You will be prompted to enter
+a string of text.
+@end table
+
+Once text is associated with a ticket it will be displayed alongside
+that ticket in the ticket browser. This particular feature lends
+itself to creating private annotations about tickets.
+
+The implementation distributed with rt-liberation allows associating
+text with tickets but is not limited to text. The same implementation
+can be extended to associate any arbitrary data with any ticket.
+
+
+@c including the relevant licenses
+@include gpl.texi
+@include fdl.texi
+
+
+
+
+
+@c --------------------------------------------------
+
+@node Concept Index
+@unnumbered Concept Index
+@printindex cp
+
+
+
+
+@c --------------------------------------------------
+
+@node Function Index
+@unnumbered Function Index
+@printindex fn
+
+
+
+
+@c --------------------------------------------------
+
+@node Variable Index
+@unnumbered Variable Index
+@printindex vr
+
+
+
+
+@c --------------------------------------------------
+
+@node Keybinding Index
+@unnumbered Keybinding Index
+@printindex ky
+
+
+@bye
diff --git a/etc/logo/rt-liberation-logo.svg b/etc/logo/rt-liberation-logo.svg
new file mode 100644
index 0000000..6469400
--- /dev/null
+++ b/etc/logo/rt-liberation-logo.svg
@@ -0,0 +1,126 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="284.81235"
+ height="415.33957"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.3.1 r9886"
+ version="1.0"
+ sodipodi:docname="ryanlerch_Frigate_Bird.svg">
+ <defs
+ id="defs4" />
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ gridtolerance="10000"
+ guidetolerance="10"
+ objecttolerance="10"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1"
+ inkscape:cx="375"
+ inkscape:cy="240"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:window-width="1280"
+ inkscape:window-height="781"
+ inkscape:window-x="0"
+ inkscape:window-y="19"
+ showgrid="false"
+ inkscape:window-maximized="0" />
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-93.47337,-145.6075)">
+ <path
+ style="fill:black"
+ d="M 168.91356,560.29545 C 167.95106,557.23004 167.1227,553.2316 163.81184,535.66978 C 161.92548,525.66397 159.25316,514.18897 157.87334,510.16978 C 155.6466,503.68366 154.92687,500.47434 153.96862,492.75839 C 153.82492,491.60132 152.9593,489.51295 152.04501,488.11758 C 151.13073,486.72221 149.43433,482.49391 148.27523,478.72136 C 147.11613,474.9488 145.30564,469.16217 144.25193,465.86217 C 140.87188,455.27661 139.28745,444.40281 139.70635,434.66627 C 140.16918,423.90874 142.11743,419.48025 150.73351,409.6009 C 153.65119,406.25544 156.92166,402.24563 158.00121,400.69021 C 160.33366,397.32964 167.28571,380.29287 167.28571,377.93753 C 167.28571,376.19357 161.29614,373.17302 155.24583,371.86579 C 153.34276,371.45461 145.93571,369.15124 138.78571,366.74718 C 124.67397,362.00235 120.65758,361.6151 103.28571,363.32434 C 97.980939,363.84628 94.409796,363.79732 93.785706,363.19409 C 92.372765,361.82839 96.029496,359.33265 99.226836,359.48048 C 101.67453,359.59366 101.65895,359.62624 98.868204,360.23048 C 97.263578,360.57791 95.793569,361.3347 95.601517,361.91223 C 95.36215,362.63205 99.581926,362.5678 109.01902,361.70792 C 116.5907,361.01802 123.65921,360.43299 124.72684,360.40786 C 126.64834,360.36263 126.64834,360.34733 124.72684,358.89397 C 123.65921,358.08647 121.43571,357.37088 119.78571,357.30379 L 116.78571,357.18179 L 119.78571,356.29191 C 121.43571,355.80248 124.36071,354.00612 126.28571,352.30001 C 132.32475,346.94764 136.49785,345.725 150.8766,345.09528 C 168.76058,344.31206 172.49239,342.67618 178.78303,332.86217 C 185.3819,322.56731 190.21978,309.91523 192.28046,297.56354 C 196.32793,273.30302 197.92528,249.53796 196.42765,235.86217 C 195.62461,228.52904 195.7054,226.45197 196.86389,224.64735 C 197.64589,223.4292 198.28739,221.6292 198.28945,220.64735 C 198.29927,215.95798 208.47301,206.29159 228.78571,191.67192 C 235.1933,187.06018 253.28622,177.36217 255.48244,177.36217 C 255.99139,177.36217 260.31783,175.51179 265.09675,173.25022 C 269.87568,170.98865 278.96071,167.42053 285.28571,165.32106 C 291.61071,163.22159 299.93571,160.2988 303.78571,158.82597 C 311.95921,155.69918 323.14593,152.21147 335.78571,148.84925 C 340.73571,147.53254 345.79821,146.15681 347.03571,145.79207 C 350.19596,144.86062 350.02063,147.65061 346.78571,149.77021 C 345.41071,150.67115 344.28571,152.05 344.28571,152.83433 C 344.28571,153.61866 342.59821,155.50865 340.53571,157.03431 C 338.47321,158.55997 335.14535,161.39538 333.14047,163.33521 C 331.13559,165.27504 325.96059,169.87107 321.64047,173.54861 C 317.32035,177.22616 308.09413,185.10116 301.13774,191.04861 C 284.5081,205.26636 269.64165,216.49356 259.86057,222.22127 C 250.03813,227.97321 247.95035,230.61055 248.12512,237.0458 C 248.19706,239.6948 248.49633,256.71217 248.79018,274.86217 C 249.29481,306.03213 249.20693,308.36127 247.20542,316.86217 C 244.92867,326.53212 244.40069,332.86549 245.64987,335.52183 C 246.21541,336.72441 245.85963,337.36263 244.35803,337.83922 C 241.15968,338.85433 241.89597,340.20458 246.03571,340.91585 C 248.09821,341.27022 254.28571,342.81072 259.78571,344.33918 C 277.81084,349.34839 293.52906,350.55177 313.28571,348.43509 C 317.96071,347.93423 327.86071,347.24755 335.28571,346.90915 C 347.56779,346.34937 352.59308,345.91995 372.03571,343.76877 C 376.52757,343.27178 378.28571,343.4056 378.28571,344.24446 C 378.28571,346.17733 374.52174,347.02888 358.28571,348.76921 C 349.76071,349.68299 336.93571,351.11429 329.78571,351.94986 C 286.71149,356.98367 289.28571,356.51195 289.28571,359.37133 C 289.28571,360.47497 290.46519,361.57769 292.34751,362.23387 C 299.02288,364.56092 350.92458,368.46948 364.31865,367.6538 C 371.36071,367.22494 373.08391,367.41408 374.18127,368.73633 C 375.30514,370.09051 375.2521,370.43784 373.83855,370.98027 C 371.6298,371.82785 321.84033,370.7459 302.78571,369.43625 C 294.53571,368.86922 284.30094,368.17183 280.04177,367.88648 C 271.61868,367.32217 264.16791,368.12517 245.92812,371.56302 C 235.7409,373.48312 233.9535,374.10575 233.2398,375.98292 C 232.7829,377.18466 231.96432,378.44276 231.42074,378.77872 C 230.87715,379.11467 228.343,382.87089 225.7893,387.12586 C 223.23559,391.38083 219.36029,397.33717 217.17752,400.36217 C 214.99474,403.38717 210.8963,409.23717 208.06987,413.36217 C 205.24344,417.48717 199.37103,425.56034 195.02005,431.30256 L 187.1092,441.74295 L 187.81984,458.30256 C 189.34317,493.79978 188.29006,503.94556 179.32772,540.11687 C 176.51701,551.46071 170.06492,563.96233 168.91356,560.29545 z M 145.83256,362.58187 L 142.98547,359.86217 L 145.24468,363.16975 C 146.48724,364.98891 147.76843,366.21278 148.09177,365.88944 C 148.4151,365.56611 147.39846,364.0777 145.83256,362.58187 z M 142.78016,362.35604 C 141.78162,361.25267 140.74775,360.56679 140.48267,360.83187 C 139.81074,361.50381 142.30489,364.36217 143.56314,364.36217 C 144.13104,364.36217 143.7787,363.45941 142.78016,362.35604 z M 149.78571,362.36217 C 148.79022,361.26217 147.52573,360.36217 146.97573,360.36217 C 146.42573,360.36217 146.79022,361.26217 147.78571,362.36217 C 148.78119,363.46217 150.04568,364.36217 150.59568,364.36217 C 151.14568,364.36217 150.78119,363.46217 149.78571,362.36217 z M 153.0721,362.16698 C 152.27044,360.95962 150.97805,359.77289 150.20012,359.5298 C 149.42219,359.28671 149.87665,360.27455 151.21002,361.72499 C 154.15915,364.93307 155.04895,365.14427 153.0721,362.16698 z M 156.85871,361.8407 C 154.80363,360.28594 153.65525,360.53306 154.74459,362.29564 C 155.10712,362.88223 156.16468,363.34786 157.09472,363.33037 C 158.57937,363.30244 158.55057,363.12067 156.85871,361.8407 z M 130.28571,361.98461 C 130.28571,361.77696 129.49821,360.98946 128.53571,360.23461 C 126.94965,358.99074 126.91428,359.02611 128.15815,360.61217 C 129.46452,362.27792 130.28571,362.80765 130.28571,361.98461 z M 104.78571,358.41515 C 107.82608,357.58781 116.96816,357.0464 116.20237,357.73903 C 115.97321,357.9463 112.63571,358.3669 108.78571,358.6737 C 104.37021,359.02555 102.89335,358.93009 104.78571,358.41515 z "
+ id="path1886" />
+ <text
+ xml:space="preserve"
+ style="font-size:154.69360352px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1;stroke:none;font-family:Monospace;-inkscape-font-specification:Monospace"
+ x="218.06105"
+ y="524.17487"
+ id="text3067"
+ sodipodi:linespacing="125%"
+ transform="scale(0.93947057,1.0644293)"><tspan
+ sodipodi:role="line"
+ id="tspan3069"
+ x="218.06105"
+ y="524.17487">RT</tspan></text>
+ </g>
+ <metadata
+ id="metadata3065">
+ <rdf:RDF>
+ <cc:Work>
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+ <dc:publisher>
+ <cc:Agent
+ rdf:about="http://openclipart.org/">
+ <dc:title>Open Clip Art Library</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ <dc:title></dc:title>
+ <dc:date>2006-12-14T21:25:31</dc:date>
+ <dc:description>a frigate bird</dc:description>
+ <dc:source>http://openclipart.org/detail/2101/frigate-bird-by-ryanlerch</dc:source>
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>ryanlerch</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag>
+ <rdf:li>bird</rdf:li>
+ <rdf:li>bird</rdf:li>
+ <rdf:li>clip art</rdf:li>
+ <rdf:li>clipart</rdf:li>
+ <rdf:li>fregatidae</rdf:li>
+ <rdf:li>fregatidae</rdf:li>
+ <rdf:li>frigate</rdf:li>
+ <rdf:li>frigate</rdf:li>
+ <rdf:li>frigate bird</rdf:li>
+ <rdf:li>frigate bird</rdf:li>
+ <rdf:li>fws</rdf:li>
+ <rdf:li>fws</rdf:li>
+ <rdf:li>fws lineart</rdf:li>
+ <rdf:li>fws lineart</rdf:li>
+ <rdf:li>image</rdf:li>
+ <rdf:li>line art</rdf:li>
+ <rdf:li>line art</rdf:li>
+ <rdf:li>media</rdf:li>
+ <rdf:li>png</rdf:li>
+ <rdf:li>public domain</rdf:li>
+ <rdf:li>remix</rdf:li>
+ <rdf:li>svg</rdf:li>
+ </rdf:Bag>
+ </dc:subject>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/publicdomain/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+</svg>
diff --git a/etc/rt-dot-el-design b/etc/rt-dot-el-design
new file mode 100644
index 0000000..01cc3c2
--- /dev/null
+++ b/etc/rt-dot-el-design
@@ -0,0 +1,60 @@
+-*- outline -*-
+
+This document outlines *a* design concept for an RT mode for
+GNU/Emacs.
+
+** Functional modules
+
+* Module "TicketSQL compiler": Symbolic expression domain specific
+ language to TicketSQL query compiler. Accept as input a sexp
+ representing a query and output a query in TicketSQL format. For
+ example: [(:and (:owner "Ben Bitdiddle") (:status "open"))] =>
+ ["Owner='Ben Bitdiddle' and Status='open'"].
+
+* Module "TicketSQL runner": Run a TicketSQL query against the server
+ and return the result. Accept as input a TicketSQL query and return
+ a list of ticket-id ticket-subject pairs or nil if no matches were
+ found.
+
+* Module "ticket retriever": Retrieve all of the data related to a
+ particular ticket. Accept as input a ticket-id and return a string
+ containing all of the information and history corresponding to the
+ ticket with ticket-id.
+
+* Module "CLI command interface": Send ticket-modifying commands to
+ the server, receive and process the results.
+
+* Module "local storage": Store and retrieve arbitrary information
+ about tickets. The storage is keyed to the RT ticket number.
+
+** User interface modules
+
+* Module "ticket browser": (requires "TicketSQL runner") Interactive
+ interface to choose a ticket out of a list of tickets. The query
+ which generated the list is displayed at the top, followed by the
+ number of tickets listed, followed by a list of tickets. Tickets are
+ displayed according to a modular display function. The tickets are
+ sorted according to a default sorting function (reverse
+ chronological order).
+
+* Module "ticket viewer": (requires "TicketSQL retriever") Interactive
+ interface to display all of the information and history
+ corresponding to the ticket with ticket-id. Ticket display provides
+ a number of convinience functions. The buffer is read-only and
+ provides font-locking to easily identify section borders. The
+ keyboard space-bar invokes `scroll-up'. The "n" and "p" keys jump to
+ the next and previous section borders respectively.
+
+** Software interfaces
+
+* Module "rt-liber-Gnus": (requires "ticket viewer") Allows the user
+ to open the current ticket in a Gnus mail buffer. Fills in the
+ "Subject:" and "To:" fields appropriately. Has the ability to import
+ the text of a certain section (automatically quoted). Optionally can
+ add a "sorry we are late" text if the ticket is old or other
+ greetings, salutations and signatures.
+
+* Module "command": (requires "CLI command interface") The user can
+ send commands to the RT system to change the status of tickets via
+ this interface. The user interface is updated as needed to reflect
+ the change.
diff --git a/rt-liberation-gnus.el b/rt-liberation-gnus.el
new file mode 100644
index 0000000..48ed6a9
--- /dev/null
+++ b/rt-liberation-gnus.el
@@ -0,0 +1,230 @@
+;;; rt-liberation-gnus.el --- Gnus integration for rt-liberation
+
+;; Copyright (C) 2009, 2012 Yoni Rabkin
+;;
+;; Authors: Yoni Rabkin <yonirabkin@member.fsf.org>
+;;
+;; 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 of the
+;; License, 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.
+;;
+;; You should have received a copy of the GNU General Public
+;; License along with this program; if not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;; MA 02111-1307, USA.
+
+;;; Installation:
+;;
+;; For installation instructions and detailed help please see the
+;; wonderful rt-liberation manual located in the "doc/" directory of
+;; the rt-liberation distribution.
+
+(defgroup rt-liber-gnus nil
+ "*Gnus integration for rt-liberation."
+ :prefix "rt-liber-gnus-"
+ :group 'rt-liber-gnus)
+
+(defcustom rt-liber-gnus-comment-address "no comment address set"
+ "*Email address for adding a comment."
+ :type 'string
+ :group 'rt-liber-gnus)
+
+(defcustom rt-liber-gnus-address "no reply address set"
+ "*Email address for replying to requestor."
+ :type 'string
+ :group 'rt-liber-gnus)
+
+(defcustom rt-liber-gnus-subject-name "no subject name set"
+ "*Subject name to be included in email header."
+ :type 'string
+ :group 'rt-liber-gnus)
+
+(defcustom rt-liber-gnus-answer-headers nil
+ "*Alist of additional message headers."
+ :type 'list
+ :group 'rt-liber-gnus)
+
+(defcustom rt-liber-gnus-provisional-tag "PROVISIONAL"
+ "*Subject line text for a provisional response."
+ :type 'string
+ :group 'rt-liber-gnus)
+
+(defcustom rt-liber-gnus-delayed-response-text
+ "Please accept my apologies for the late reply."
+ "*Text for a belated reply."
+ :type 'string
+ :group 'rt-liber-gnus)
+
+(defcustom rt-liber-gnus-signature
+ "--
+ Regards."
+ "Signature to append to email."
+ :type 'string
+ :group 'rt-liber-gnus)
+
+(defcustom rt-liber-gnus-subject-regexp
+ ""
+ "Regular expression to capture the ticket number in the subject
+line of an email. For example: \\[company.com #\\([0-9].+?\\)\\]"
+ :type 'string
+ :group 'rt-liber-gnus)
+
+(require 'rt-liberation)
+
+(eval-when-compile (require 'gnus-msg))
+
+(defun rt-liber-gnus-compose (addr ticket-alist options)
+ "Create a Gnus *mail* buffer for the RT email interface.
+ADDR email address.
+TICKET-ALIST association list of ticket properties.
+OPTIONS association list of options.
+"
+ (let ((provisional (cdr (assoc 'provisional options)))
+ (suppress-subject (cdr (assoc 'suppress-subject options)))
+ (top-matter (cdr (assoc 'top-matter options)))
+ (contents (cdr (assoc 'contents options)))
+ (no-comment (cdr (assoc 'no-comment options))))
+ (gnus-setup-message 'message
+ (message-mail
+ addr
+ (format "[%s #%s] %s"
+ rt-liber-gnus-subject-name
+ (rt-liber-ticket-id-only ticket-alist)
+ (cond (suppress-subject "")
+ (provisional rt-liber-gnus-provisional-tag)
+ (t (rt-liber-format "Re: %s" ticket-alist))))
+ rt-liber-gnus-answer-headers
+ nil
+ 'switch-to-buffer))
+ (goto-char (point-max))
+ (save-excursion
+ (when top-matter (insert top-matter))
+ (let ((start (point)))
+ (when contents (newline 2) (insert contents))
+ (when (not no-comment)
+ (comment-region start (point))))
+ (newline 2)
+ (insert rt-liber-gnus-signature)
+ (newline))))
+
+;; fixme: test against both versions of the RT CLI
+(defun rt-liber-gnus-content-to-string ()
+ "Return the current content section as a string"
+ (rt-liber-gnus-with-ticket-buffer
+ (goto-char (point-at-eol))
+ (when
+ (not
+ (or (re-search-backward rt-liber-content-regexp (point-min) t)
+ (re-search-forward rt-liber-content-regexp (point-max) t)))
+ (error "no content sections found"))
+ (goto-char (point-at-bol))
+ (re-search-forward "^Content: " (point-at-eol) nil)
+ (let ((start (point))
+ text)
+ (re-search-forward "^[[:alpha:]]+:" (point-max) t)
+ (forward-line -1)
+ (if (= (count-lines start (point)) 1)
+ (error "empty content section")
+ (setq text (buffer-substring-no-properties start (point)))
+ (with-temp-buffer
+ (insert text)
+ (goto-char (point-min))
+ (replace-regexp "^[ ]+" "")
+ (whitespace-cleanup)
+ (setq text (buffer-substring (point-min) (point-max)))))
+ text)))
+
+(defmacro rt-liber-gnus-with-ticket-buffer (&rest body)
+ `(progn
+ (when (not (boundp 'rt-liber-ticket-local))
+ (error "rt-liberation ticket view buffer not present"))
+ ,@body))
+
+(defun rt-liber-gnus-compose-reply-to-requestor ()
+ (interactive)
+ (rt-liber-gnus-with-ticket-buffer
+ (rt-liber-gnus-compose
+ rt-liber-gnus-address
+ rt-liber-ticket-local
+ nil)))
+
+(defun rt-liber-gnus-compose-reply-to-requestor-to-this ()
+ (interactive)
+ (rt-liber-gnus-with-ticket-buffer
+ (rt-liber-gnus-compose
+ rt-liber-gnus-address
+ rt-liber-ticket-local
+ `((contents . ,(rt-liber-gnus-content-to-string))
+ (top-matter . ,(if (rt-liber-ticket-old-p rt-liber-ticket-local)
+ rt-liber-gnus-delayed-response-text
+ nil))))))
+
+(defun rt-liber-gnus-compose-reply-to-requestor-verbatim-this ()
+ (interactive)
+ (rt-liber-gnus-with-ticket-buffer
+ (rt-liber-gnus-compose
+ rt-liber-gnus-address
+ rt-liber-ticket-local
+ `((contents . ,(rt-liber-gnus-content-to-string))
+ (no-comment . t)))))
+
+(defun rt-liber-gnus-compose-provisional ()
+ (interactive)
+ (rt-liber-gnus-with-ticket-buffer
+ (rt-liber-gnus-compose
+ rt-liber-gnus-comment-address
+ rt-liber-ticket-local
+ '((provisional . t)))))
+
+(defun rt-liber-gnus-compose-provisional-to-this ()
+ (interactive)
+ (rt-liber-gnus-with-ticket-buffer
+ (rt-liber-gnus-compose
+ rt-liber-gnus-comment-address
+ rt-liber-ticket-local
+ `((provisional . t)
+ (contents . ,(rt-liber-gnus-content-to-string))
+ (top-matter . ,(if (rt-liber-ticket-old-p rt-liber-ticket-local)
+ rt-liber-gnus-delayed-response-text
+ nil))))))
+
+(defun rt-liber-gnus-compose-comment ()
+ (interactive)
+ (rt-liber-gnus-with-ticket-buffer
+ (rt-liber-gnus-compose
+ rt-liber-gnus-comment-address
+ rt-liber-ticket-local
+ `((suppress-subject . t)
+ (no-comment . t)
+ ))))
+
+(defun rt-liber-gnus-compose-comment-this ()
+ (interactive)
+ (rt-liber-gnus-with-ticket-buffer
+ (rt-liber-gnus-compose
+ rt-liber-gnus-comment-address
+ rt-liber-ticket-local
+ `((suppress-subject . t)
+ (contents . ,(rt-liber-gnus-content-to-string))
+ ))))
+
+(defun rt-liber-gnus-visit-ticket-at-point ()
+ "Call `rt-liber-display-ticket' on this ticket."
+ (interactive)
+ (save-excursion
+ (goto-char (point-at-bol))
+ (re-search-forward rt-liber-gnus-subject-regexp (point-at-eol) nil))
+ (let ((match (match-string-no-properties 1)))
+ (when (not match)
+ (error "no ticket number found in subject line"))
+ (rt-liber-display-ticket match)))
+
+(provide 'rt-liberation-gnus)
+
+;;; rt-liberation-gnus.el ends here.
diff --git a/rt-liberation-multi.el b/rt-liberation-multi.el
new file mode 100644
index 0000000..3e9c208
--- /dev/null
+++ b/rt-liberation-multi.el
@@ -0,0 +1,113 @@
+;;; rt-liberation-multi.el --- Free from RT
+
+;; Copyright (C) 2010 Yoni Rabkin
+;;
+;; Authors: Yoni Rabkin <yonirabkin@member.fsf.org>
+;;
+;; 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 of the
+;; License, 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.
+;;
+;; You should have received a copy of the GNU General Public
+;; License along with this program; if not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;; MA 02111-1307, USA.
+
+;;; Code:
+
+(require 'rt-liberation)
+
+(defface rt-liber-marked-ticket-face
+ '((((class color) (background dark))
+ (:foreground "Red"))
+ (((class color) (background light))
+ (:foreground "Red"))
+ (((type tty) (class mono))
+ (:inverse-video t))
+ (t (:background "Red")))
+ "Face for marked tickets in browser buffer.")
+
+(defvar rt-liber-marked-tickets nil
+ "Marked tickets (becomes ticket-browser buffer local).")
+
+(defun rt-liber-ticket-marked-p (ticket)
+ "Return a truth value if TICKET is marked, otherwise NIL."
+ (let ((ticket-id (rt-liber-ticket-id-only ticket)))
+ (member ticket-id rt-liber-marked-tickets)))
+
+(defun rt-liber-mark-ticket-at-point ()
+ "Mark/unmark the ticket at point for future action."
+ (interactive)
+ (let ((ticket (get-text-property (point) 'rt-ticket)))
+ (if ticket
+ (let ((ticket-id (rt-liber-ticket-id-only ticket))
+ (inhibit-read-only t))
+ (set (make-local-variable 'rt-liber-marked-tickets)
+ (if (rt-liber-ticket-marked-p ticket)
+ (remove ticket-id rt-liber-marked-tickets)
+ (append (list ticket-id) rt-liber-marked-tickets)))
+ (let ((p (point)))
+ (rt-liber-ticketlist-browser-redraw
+ rt-liber-ticket-list
+ rt-liber-query)
+ (goto-char p)
+ (rt-liber-next-ticket-in-browser)
+ (recenter-top-bottom)))
+ (error "no ticket at point"))))
+
+(defun rt-liber-multi-set-status-open ()
+ "Set the status of all marked tickets to `open'."
+ (interactive)
+ (when (not rt-liber-marked-tickets)
+ (error "no marked tickets"))
+ (dolist (ticket-id rt-liber-marked-tickets)
+ (message "setting status for ticket #%s ..." ticket-id)
+ (rt-liber-command-set-status-open ticket-id)
+ (message "setting status for ticket #%s ...done" ticket-id))
+ (rt-liber-browser-refresh))
+
+(defun rt-liber-multi-set-status-resolved ()
+ "Set the status of all marked tickets to `resolve'."
+ (interactive)
+ (when (not rt-liber-marked-tickets)
+ (error "no marked tickets"))
+ (dolist (ticket-id rt-liber-marked-tickets)
+ ;; these are less for the user and more to leave a trail in the
+ ;; `*Messages*' buffer
+ (message "setting status for ticket #%s ..." ticket-id)
+ (rt-liber-command-set-status-resolved ticket-id))
+ (rt-liber-browser-refresh))
+
+(defun rt-liber-multi-assign (name)
+ "Assign marked tickets to a user NAME."
+ (interactive "sAssign to: ")
+ (when (not rt-liber-marked-tickets)
+ (error "no marked tickets"))
+ (dolist (ticket-id rt-liber-marked-tickets)
+ (message "setting status for ticket #%s ..." ticket-id)
+ (rt-liber-command-set-owner
+ ticket-id name))
+ (rt-liber-browser-refresh))
+
+(defun rt-liber-multi-flag-as-spam-and-delete ()
+ "Flag all marked tickets as spam, and delete them."
+ (interactive)
+ (when (not rt-liber-marked-tickets)
+ (error "no marked tickets"))
+ (dolist (ticket-id rt-liber-marked-tickets)
+ (rt-liber-command-set-cf
+ ticket-id
+ (rt-liber-command-get-custom-field-string
+ 'cf-is-spam) "yes")
+ (rt-liber-command-set-status-deleted ticket-id))
+ (rt-liber-browser-refresh))
+
+(provide 'rt-liberation-multi)
+
+;;; rt-liberation-multi.el ends here.
diff --git a/rt-liberation-storage.el b/rt-liberation-storage.el
new file mode 100644
index 0000000..8bcb96b
--- /dev/null
+++ b/rt-liberation-storage.el
@@ -0,0 +1,110 @@
+;;; rt-liberation-storage.el --- Storage backend for rt-liberation
+
+;; Copyright (C) 2010 Yoni Rabkin
+;;
+;; Author: Yoni Rabkin <yonirabkin@member.fsf.org>
+;;
+;; 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 of the
+;; License, 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.
+;;
+;; You should have received a copy of the GNU General Public
+;; License along with this program; if not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;; MA 02111-1307, USA.
+
+;;; Code:
+
+(require 'rt-liberation)
+
+(defvar rt-liber-store nil
+ "In memory storage for ticket metadata.")
+
+(defvar rt-liber-store-file "ticket_metadata"
+ "File name for storing ticket metadata.")
+
+(defvar rt-liber-ancillary-format-f 'rt-liber-ancillary-format-f
+ "Default formatting function for ancillary data.")
+
+(defun rt-liber-store-write ()
+ "Write `rt-liber-store' to permanent storage."
+ (when (and (stringp rt-liber-directory)
+ (not (file-exists-p rt-liber-directory)))
+ (make-directory rt-liber-directory))
+ (when (hash-table-p rt-liber-store)
+ (with-temp-buffer
+ (insert (format "%s" rt-liber-store))
+ (insert "\n")
+ (write-file
+ (concat (file-name-as-directory rt-liber-directory)
+ rt-liber-store-file)))))
+
+(defun rt-liber-store-read ()
+ "Populate `rt-liber-store' from permanent storage."
+ (let ((file (concat (file-name-as-directory rt-liber-directory)
+ rt-liber-store-file)))
+ (when (file-exists-p file)
+ (setq rt-liber-store
+ (with-temp-buffer
+ (insert-file-contents file)
+ (read (current-buffer)))))))
+
+(defun rt-liber-store-load ()
+ "Ensure that the store has been loaded."
+ (when (not (hash-table-p rt-liber-store))
+ (rt-liber-store-read)))
+
+(defun rt-liber-store-ticket-property (key value ticket-id)
+ "Relate KEY and VALUE to TICKET-ID."
+ (rt-liber-store-load)
+ (let ((existing (gethash ticket-id rt-liber-store)))
+ (when (not existing)
+ (setq existing (make-hash-table :test 'equal)))
+ (puthash key value existing)
+ (puthash ticket-id existing rt-liber-store)
+ (rt-liber-store-write)))
+
+
+;;; ------------------------------------------------------------------
+;;; Interface
+;;; ------------------------------------------------------------------
+
+(defun rt-liber-set-ancillary-text (text)
+ "Store ancillary string TEXT for the ticket at point."
+ (let ((id (rt-liber-browser-ticket-id-at-point))
+ (inhibit-read-only t)
+ message)
+ (rt-liber-store-ticket-property "text" text id)
+ (if (and rt-liber-ticket-list rt-liber-query)
+ (rt-liber-ticketlist-browser-redraw
+ rt-liber-ticket-list rt-liber-query)
+ (setq message " (refresh ticket-browser to see changes)"))
+ (rt-liber-browser-move-point-to-ticket id)
+ (minibuffer-message "stored text for ticket %s%s"
+ id (or message ""))))
+
+(defun rt-liber-get-ancillary-text (ticket-id)
+ "Return the TEXT field for TICKET-ID or an empty string."
+ (rt-liber-store-load)
+ (let ((existing (gethash ticket-id rt-liber-store)))
+ (if existing
+ (or (gethash "text" existing) "")
+ "")))
+
+(defun rt-liber-ancillary-format-f (ticket-id)
+ "Default formatting function for ancillary data."
+ (rt-liber-get-ancillary-text ticket-id))
+
+(defun rt-liber-get-anc (ticket-id)
+ "Return formatted ancillary data string for ticket TICKET-ID."
+ (funcall rt-liber-ancillary-format-f ticket-id))
+
+(provide 'rt-liberation-storage)
+
+;;; rt-liberation-storage.el ends here.
diff --git a/rt-liberation-update.el b/rt-liberation-update.el
new file mode 100644
index 0000000..8c57bf8
--- /dev/null
+++ b/rt-liberation-update.el
@@ -0,0 +1,106 @@
+;;; rt-liberation-update.el --- check updated tickets
+
+;; Copyright (C) 2009 Yoni Rabkin
+;;
+;; Authors: Yoni Rabkin <yonirabkin@member.fsf.org>
+;;
+;; 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 of the
+;; License, 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.
+;;
+;; You should have received a copy of the GNU General Public
+;; License along with this program; if not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;; MA 02111-1307, USA.
+
+;;; Installation:
+;;
+;; For installation instructions and detailed help please see the
+;; wonderful rt-liberation manual located in the "doc/" directory of
+;; the rt-liberation distribution.
+
+;;; Usage:
+;;
+
+(require 'rt-liberation)
+
+(defgroup rt-liber-update nil
+ "*Check updates for rt-liberation."
+ :prefix "rt-liber-update-"
+ :group 'rt-liber-update)
+
+(defcustom rt-liber-update-file
+ (concat (file-name-as-directory rt-liber-directory) "update")
+ "*File to store update information."
+ :type 'string
+ :group 'rt-liber-update)
+
+(defcustom rt-liber-update-default-queue nil
+ "*Default queue to run queries against."
+ :type 'string
+ :group 'rt-liber-update)
+
+(defun rt-liber-update-timestamp ()
+ "Write the current time to disk as a time-stamp."
+ (rt-liber-update-write (format "%s" (current-time))))
+
+(defun rt-liber-update-write (str)
+ "Write STR to disk under the rt-liber directory."
+ (when (and (stringp rt-liber-directory)
+ (not (file-exists-p rt-liber-directory)))
+ (make-directory rt-liber-directory))
+ (when (stringp rt-liber-update-file)
+ (with-temp-buffer
+ (insert str)
+ (insert "\n")
+ (write-file rt-liber-update-file))))
+
+(defun rt-liber-update-read ()
+ "Return the time-stamp read from disk or the current time."
+ (when (file-exists-p rt-liber-update-file)
+ (let ((timestamp (current-time)))
+ (with-temp-buffer
+ (insert-file-contents rt-liber-update-file)
+ (setq timestamp (read (current-buffer))))
+ timestamp)))
+
+(defun rt-liber-update-run-query (query-queue timestamp)
+ "Run query on QUERY-QUEUE since TIMESTAMP."
+ (rt-liber-browse-query
+ (rt-liber-compile-query
+ (and (queue query-queue)
+ (lastupdated nil
+ (format-time-string "%Y-%m-%d"
+ timestamp))))))
+
+(defun rt-liber-update (&optional no-update)
+ "Show tickets last updated since `rt-liber-update' last run.
+
+With the NO-UPDATE prefix, don't update the time-stamp on disk.
+
+If no time-stamp is found, for instance when you run this for the
+first time, today's date is used and then recorded as the
+time-stamp."
+ (interactive "P")
+ (when (not rt-liber-update-default-queue)
+ (error "`rt-liber-update-default-queue' is nil"))
+ (let ((timestamp (rt-liber-update-read)))
+ (rt-liber-update-run-query rt-liber-update-default-queue
+ timestamp)
+ (when (not no-update)
+ (rt-liber-update-timestamp))
+ (message "showing tickets updated after: %s (time-stamp %s)"
+ (format-time-string "%Y-%m-%d" timestamp)
+ (if no-update
+ "not updated"
+ "updated"))))
+
+(provide 'rt-liberation-update)
+
+;;; rt-liberation-update.el ends here.
diff --git a/rt-liberation.el b/rt-liberation.el
new file mode 100644
index 0000000..6f31921
--- /dev/null
+++ b/rt-liberation.el
@@ -0,0 +1,1276 @@
+;;; rt-liberation.el --- Free from RT
+
+;; Copyright (C) 2008, 2009, 2010, 2011 Yoni Rabkin, Aaron S. Hawley,
+;; John Sullivan
+;;
+;; Authors: Yoni Rabkin <yonirabkin@member.fsf.org>, Aaron S. Hawley
+;; <aaron.s.hawley@gmail.com>, John Sullivan <johnsu01@wjsullivan.net>
+;;
+;; 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 of the
+;; License, 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.
+;;
+;; You should have received a copy of the GNU General Public
+;; License along with this program; if not, write to the Free
+;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+;; MA 02111-1307, USA.
+
+;;; Installation and Use:
+;;
+;; Detailed instructions for installation and use can be found in the
+;; rt-liberation manual, in the doc/ directory of the distribution.
+
+;;; History:
+;;
+;; Started near the end of 2008.
+
+;;; Code:
+
+(require 'browse-url)
+(require 'time-date)
+(require 'cl)
+
+(defgroup rt-liber nil
+ "*rt-liberation, the Emacs interface to RT"
+ :prefix "rt-liber-"
+ :group 'rt-liber)
+
+(defcustom rt-liber-directory "~/.emacs.d/rt-liber"
+ "*Directory to store persistent information."
+ :type 'string
+ :group 'rt-liber)
+
+(defvar rt-liber-created-string "Created"
+ "String representation of \"created\" query tag.")
+
+(defvar rt-liber-base-url ""
+ "Base url for ticket display.")
+
+(defvar rt-liber-lastupdated-string "LastUpdated"
+ "String representation of \"lastupdated\" query tag.")
+
+(defvar rt-liber-content-string "Content LIKE"
+ "String representation of \"content\" query tag.")
+
+(defvar rt-liber-subject-string "Subject LIKE"
+ "String representation of \"subject\" query tag.")
+
+(defvar rt-liber-email-address-string "Requestor.EmailAddress LIKE"
+ "String representation of \"Requestor.EmailAddress\" query tag.")
+
+(defvar rt-liber-content-not-string "Content NOT LIKE"
+ "String representation of \"content\" query tag.")
+
+(defvar rt-liber-subject-not-string "Subject NOT LIKE"
+ "String representation of \"subject\" query tag.")
+
+(defvar rt-liber-email-address-not-string "Requestor.EmailAddress NOT LIKE"
+ "String representation of \"Requestor.EmailAddress\" query tag.")
+
+(defvar rt-liber-content-regexp "^Content:.*$"
+ "Regular expression for section headers.")
+
+(defvar rt-liber-correspondence-regexp
+ "^Type: \\(EmailRecord\\|CommentEmailRecord\\|Correspond\\)"
+ "Regular expression for correspondence sections.")
+
+(defvar rt-liber-rt-binary "~/rt-3.8.1/bin/rt"
+ "Location of the RT CLI binary.")
+
+(defvar rt-liber-rt-version "3.8.1"
+ "Version of the RT CLI.")
+
+(defvar rt-liber-username nil
+ "Username for assigning ownership on the RT server.")
+
+(defvar rt-liber-browser-buffer-name "*ticket-browser*"
+ "Name of ticket browser buffer.")
+
+(defvar rt-liber-browser-buffer nil
+ "Ticket browser buffer.")
+
+(defvar rt-liber-browser-default-sorting-function
+ 'rt-liber-sort-by-time-created
+ "Default sorting function.")
+
+(defvar rt-liber-browser-default-filter-function
+ 'rt-liber-default-filter-f
+ "Default filtering function.
+
+This is a function which accepts the ticket alist as a single
+argument and returns nil if the ticket needs to be filtered out,
+dropped or ignored (however you wish to put it.), otherwise the
+function returns a truth value.")
+
+(defvar rt-liber-custom-ticket-redraw-function
+ 'rt-liber-ticketlist-browser-redraw-f
+ "Default ticket redraw function.")
+
+(defvar rt-liber-ticket-old-threshold 30
+ "Age in days before a ticket is considered old.")
+
+(defvar rt-liber-jump-to-latest nil
+ "jump to the latest correspondence when viewing a ticket.")
+
+(defvar rt-liber-anc-p nil
+ "Display ancillary data for tickets.")
+
+(defvar rt-liber-ticket-list nil
+ "Ticket-list structure (becomes ticket-browser buffer local).")
+
+(defvar rt-liber-query nil
+ "Query structure (becomes ticket-browser buffer local).")
+
+(defface rt-liber-ticket-face
+ '((((class color) (background dark))
+ (:foreground "DarkSeaGreen"))
+ (((class color) (background light))
+ (:foreground "Blue"))
+ (((type tty) (class mono))
+ (:inverse-video t))
+ (t (:background "Blue")))
+ "Face for tickets in browser buffer.")
+
+(defconst rt-liber-viewer-font-lock-keywords
+ (let ((header-regexp (regexp-opt '("id: " "Ticket: " "TimeTaken: "
+ "Type: " "Field: " "OldValue: "
+ "NewValue: " "Data: "
+ "Description: " "Created: "
+ "Creator: " "Attachments: ") t)))
+ (list
+ (list (concat "^" header-regexp ".*$") 0
+ 'font-lock-comment-face)))
+ "Expressions to font-lock for RT ticket viewer.")
+
+(defvar rt-liber-browser-do-refresh t
+ "When t, run `rt-liber-browser-refresh' otherwise disable it.")
+
+(defvar rt-liber-command-dictionary
+ '((comment . "comment")
+ (edit . "edit"))
+ "Mapping between command symbols and command strings.
+
+The command symbols provide the programmer with a consistent way
+of referring to certain commands. The command strings are the
+specific strings which would produce the desired effect in the
+server.")
+
+(defvar rt-liber-status-dictionary
+ '((deleted . "deleted")
+ (resolved . "resolved")
+ (open . "open"))
+ "Mapping between status symbols and status strings.
+
+The status symbols provide the programmer with a consistent way
+of referring to certain statuses. The status strings are the
+server specific strings.")
+
+(defvar rt-liber-custom-field-dictionary
+ '((cf-is-spam . "cf-is-spam"))
+ "Mapping between custom field symbols and custom field strings.
+
+The custom field symbols provide the programmer with a consistent
+way of referring to certain custom fields. The custom field
+strings are the server specific strings.")
+
+
+;;; --------------------------------------------------------
+;;; TicketSQL compiler
+;;; --------------------------------------------------------
+
+(defun rt-liber-bool-p (sym)
+ "Return t if SYM is a boolean operator, otherwise nil."
+ (member sym '(and or)))
+(defun rt-liber-attrib-p (sym)
+ "Return t if SYM is a ticket attribute, otherwise nil."
+ (member sym '(id owner status subject content queue lastupdatedby
+ email-address)))
+(defun rt-liber-time-p (sym)
+ "Return t if SYM is a temporal attribute, otherwise nil."
+ (member sym '(created lastupdated)))
+(defun rt-liber-negation-p (sym)
+ (member sym '(not)))
+
+(defun rt-liber-reduce (op seq)
+ "Reduce-OP with SEQ to a string of \"s0 op s1 op s2..\"."
+ (if seq
+ (reduce
+ #'(lambda (a b)
+ (format "%s %s %s" a op b))
+ seq)
+ ""))
+
+(defun rt-liber-make-interval (pred before after)
+ "Return a formatted TicketSQL interval.
+PRED temporal attribute predicate.
+BEFORE date before predicate.
+AFTER date after predicate."
+ (when (string= before "") (setq before nil))
+ (when (string= after "") (setq after nil))
+ (concat
+ (if before (format "%s < '%s'" pred before) "")
+ (if (and before after) (format " AND ") "")
+ (if after (format "%s > '%s'" pred after) "")))
+
+(defmacro rt-liber-compile-query (query &optional n)
+ "Compile sexp-based QUERY into TicketSQL."
+ (cond ((null query) `"")
+ ((stringp query) `,query)
+ ((rt-liber-bool-p query) `,(upcase (format "%s" query)))
+ ;; attribute (positive)
+ ((and (rt-liber-attrib-p query)
+ (not n))
+ `,(cond ((equal query 'content) rt-liber-content-string)
+ ((equal query 'subject) rt-liber-subject-string)
+ ((equal query 'email-address) rt-liber-email-address-string)
+ (t (capitalize (format "%s =" query)))))
+ ;; attribute (negation)
+ ((and (rt-liber-attrib-p query)
+ n)
+ `,(cond ((equal query 'content) rt-liber-content-not-string)
+ ((equal query 'subject) rt-liber-subject-not-string)
+ ((equal query 'email-address) rt-liber-email-address-not-string)
+ (t (capitalize (format "%s !=" query)))))
+ ;; time
+ ((rt-liber-time-p query)
+ `,(cond ((equal query 'created) rt-liber-created-string)
+ ((equal query 'lastupdated) rt-liber-lastupdated-string)))
+ ((and (listp query)
+ (rt-liber-time-p (car query)))
+ `(rt-liber-make-interval
+ (rt-liber-compile-query ,(car query))
+ (rt-liber-compile-query ,(cadr query))
+ (rt-liber-compile-query ,(caddr query))))
+ ;; function (known at compile time?)
+ ((and query
+ (listp query)
+ (not (rt-liber-bool-p (car query)))
+ (not (rt-liber-negation-p (car query)))
+ (functionp (car query)))
+ `(format "%s" ,query))
+ ;; negation attribute pairs
+ ((and (listp query)
+ (rt-liber-negation-p (car query))
+ (rt-liber-attrib-p (caadr query)))
+ `(format "%s '%s'"
+ (rt-liber-compile-query ,(caadr query) t) ; negate
+ (rt-liber-compile-query ,(cadadr query))))
+ ;; attribute pairs
+ ((and (listp query)
+ (rt-liber-attrib-p (car query)))
+ `(format "%s '%s'"
+ (rt-liber-compile-query ,(car query))
+ (rt-liber-compile-query ,(cadr query))))
+ ;; splice boolean operators
+ ((and (listp query)
+ (rt-liber-bool-p (car query)))
+ `(rt-liber-reduce (rt-liber-compile-query ,(car query))
+ (rt-liber-compile-query ,(cdr query))))
+ ;; compound statements
+ ((and (listp query)
+ (not (cdr query)))
+ `(list (rt-liber-compile-query ,(car query))))
+ ((listp query)
+ `(append
+ (list (rt-liber-compile-query ,(car query)))
+ (rt-liber-compile-query ,(cdr query))))
+ ;; free variable
+ ((and query
+ (symbolp query))
+ `(format "%s" ,query))
+ (t (error "cannot compile query %s" query))))
+
+
+;;; --------------------------------------------------------
+;;; Query runner
+;;; --------------------------------------------------------
+
+(defun rt-liber-query-runner (op query-string)
+ "Run OP query against the server with QUERY-STRING."
+ (message "started '%s' query at %s..." op (current-time-string))
+ (condition-case excep
+ (with-temp-buffer
+ (if (and (not (rt-liber-version-< rt-liber-rt-version
+ "3.8.2"))
+ (string= op "show"))
+ (call-process rt-liber-rt-binary nil t nil
+ op "-l" query-string)
+ (call-process rt-liber-rt-binary nil t nil
+ op query-string))
+ (message "query ended at %s" (current-time-string))
+ (buffer-string))
+ (file-error
+ (error "could not find the RT binary at: %s" rt-liber-rt-binary))
+ (error "an unhandled exception occured: %s" excep)))
+
+(defun rt-liber-parse-answer (answer-string parser-f)
+ "Operate on ANSWER-STRING with PARSER-F."
+ (with-temp-buffer
+ (insert answer-string)
+ (goto-char (point-min))
+ (funcall parser-f)))
+
+
+;;; --------------------------------------------------------
+;;; TicketSQL runner
+;;; --------------------------------------------------------
+
+(defun rt-liber-ticketsql-runner-parser-f ()
+ "Parser function for a textual list of tickets."
+ (let (idsub-list)
+ (while (or
+ (and (not (rt-liber-version-< rt-liber-rt-version
+ "3.8.2"))
+ (re-search-forward "^ *\\([0-9]+\\) *\\(.*\\)$"
+ (point-max) t))
+ (re-search-forward "^\\([0-9]+\\): \\(.*\\)$"
+ (point-max) t))
+ (push (list (match-string-no-properties 1)
+ (match-string-no-properties 2))
+ idsub-list))
+ idsub-list))
+
+(defun rt-liber-run-ls-query (query)
+ "Run an \"ls\" type query against the server with QUERY."
+ (rt-liber-parse-answer
+ (rt-liber-query-runner "ls" query)
+ 'rt-liber-ticketsql-runner-parser-f))
+
+
+;;; --------------------------------------------------------
+;;; Ticket list retriever
+;;; --------------------------------------------------------
+
+(put 'rt-liber-no-result-from-query-error
+ 'error-conditions
+ '(error rt-liber-errors rt-liber-no-result-from-query-error))
+
+(put 'rt-liber-no-result-from-query-error
+ 'error-message
+ "No results from query")
+
+(defun rt-liber-ticket-base-retriever-parser-f ()
+ "Parser function for ticket list."
+ (let (ticketbase-list ticketbase (continue t))
+ (while (save-excursion
+ (re-search-forward "[A-Za-z]" (point-max) t)) ; really?
+ (while (and continue
+ (re-search-forward
+ "^\\(\\([\.{} #[:alpha:]]+\\): \\(.*\\)\\)$\\|^--$"
+ (point-max) t))
+ (if (string= (match-string-no-properties 0) "--")
+ (setq continue nil)
+ (push (cons (match-string-no-properties 2)
+ (match-string-no-properties 3))
+ ticketbase)))
+ (push (copy-seq ticketbase) ticketbase-list)
+ (setq ticketbase nil
+ continue t))
+ ticketbase-list))
+
+;; accept the output of `rt-liber-ticketsql-runner-parser-f' and
+;; return a string suitable for an RT "show" query
+(defun rt-liber-create-tickets-string (idsublist)
+ "Create a RT CLI ticket \"show\" string from IDSUBLIST."
+ (let ((ticket-list (mapcar #'(lambda (e) (car e)) idsublist)))
+ (if ticket-list
+ (concat "ticket/"
+ (if (= (length ticket-list) 1)
+ (format "%s" (car ticket-list))
+ (reduce
+ #'(lambda (a b)
+ (format "%s,%s" a b))
+ ticket-list)))
+ (signal 'rt-liber-no-result-from-query-error nil))))
+
+(defun rt-liber-run-show-base-query (idsublist)
+ "Run \"show\" type query against the server with IDSUBLIST."
+ (rt-liber-parse-answer
+ (rt-liber-query-runner "show"
+ (rt-liber-create-tickets-string idsublist))
+ #'rt-liber-ticket-base-retriever-parser-f))
+
+
+;;; --------------------------------------------------------
+;;; Ticket retriever
+;;; --------------------------------------------------------
+
+;; Implementation note: Working with 3.8.1 or 3.8.2 of the RT CLI
+;; makes a huge difference here. 3.8.1 returns a kind of listing of
+;; the history ID objects which requires further processing. 3.8.2 on
+;; the other hand returns the contents of all the ticket history
+;; objects in one fell swoop.
+
+(defun rt-liber-create-ticket-history-string (ticket-id)
+ "Create a query for TICKET-ID to retrieve all history objects."
+ (concat "ticket/" ticket-id "/history/id"))
+
+(defun rt-liber-create-ticket-histories-string (ticket-id subid-list)
+ "Create query for TICKET-ID to retrieve SUBID-LIST objects."
+ (concat "ticket/" ticket-id "/history/id/"
+ (reduce
+ #'(lambda (a b) (format "%s,%s" a b)) subid-list)))
+
+(defun rt-liber-run-ticket-history-base-query (ticket-id)
+ "Run history query against server for TICKET-ID."
+ (rt-liber-parse-answer
+ (rt-liber-query-runner "show"
+ (rt-liber-create-ticket-history-string
+ ticket-id))
+ (if (rt-liber-version-< rt-liber-rt-version "3.8.2")
+ #'(lambda ()
+ (let ((ticket-history-sublist nil))
+ (goto-char (point-min))
+ (while (re-search-forward "^\\([0-9]+\\): " (point-max) t)
+ (setq ticket-history-sublist
+ (append (list (match-string-no-properties 1))
+ ticket-history-sublist)))
+ (if ticket-history-sublist
+ (rt-liber-parse-answer
+ (rt-liber-query-runner
+ "show"
+ (rt-liber-create-ticket-histories-string
+ ticket-id
+ ticket-history-sublist))
+ #'(lambda () (buffer-substring (point-min)
+ (point-max))))
+ (error "an unhandled exceptions occurred"))))
+ #'(lambda () (buffer-substring (point-min) (point-max))))))
+
+
+;;; --------------------------------------------------------
+;;; Ticket utilities
+;;; --------------------------------------------------------
+
+(defun rt-liber-ticket-days-old (ticket-alist)
+ "Return the age of the ticket in positive days."
+ (days-between (format-time-string "%Y-%m-%dT%T%z" (current-time))
+ (cdr (assoc "Created" ticket-alist))))
+
+(defun rt-liber-ticket-old-p (ticket-alist)
+ (<= rt-liber-ticket-old-threshold
+ (rt-liber-ticket-days-old ticket-alist)))
+
+
+;;; --------------------------------------------------------
+;;; Ticket viewer
+;;; --------------------------------------------------------
+
+(defun rt-liber-jump-to-latest-correspondence ()
+ "Move point to the newest correspondence section."
+ (interactive)
+ (let (latest-point)
+ (save-excursion
+ (goto-char (point-max))
+ (when (re-search-backward rt-liber-correspondence-regexp
+ (point-min) t)
+ (setq latest-point (point))))
+ (if latest-point
+ (progn
+ (goto-char latest-point)
+ (rt-liber-next-section-in-viewer))
+ (message "no correspondence found"))))
+
+(defun rt-liber-ticket-id-only (ticket-alist)
+ "Return numerical portion of ticket number from TICKET-ALIST."
+ (if ticket-alist
+ (substring (cdr (assoc "id" ticket-alist)) 7)
+ nil))
+
+(defun rt-liber-viewer-visit-in-browser ()
+ "Visit this ticket in the RT Web interface."
+ (interactive)
+ (let ((id (rt-liber-ticket-id-only rt-liber-ticket-local)))
+ (if id
+ (browse-url
+ (concat rt-liber-base-url "Ticket/Display.html?id=" id))
+ (error "no ticket currently in view"))))
+
+(defun rt-liber-viewer-mode-quit ()
+ "Bury the ticket viewer."
+ (interactive)
+ (bury-buffer))
+
+(defun rt-liber-viewer-show-ticket-browser ()
+ "Return to the ticket browser buffer."
+ (interactive)
+ (let ((id (rt-liber-ticket-id-only rt-liber-ticket-local)))
+ (if id
+ (let ((target-buffer
+ (if rt-liber-assoc-browser
+ (buffer-name rt-liber-assoc-browser)
+ (buffer-name rt-liber-browser-buffer-name))))
+ (if target-buffer
+ (switch-to-buffer target-buffer)
+ (error "associated ticket browser buffer no longer exists"))
+ (rt-liber-browser-move-point-to-ticket id))
+ (error "no ticket currently in view"))))
+
+(defun rt-liber-next-section-in-viewer ()
+ "Move point to next section."
+ (interactive)
+ (forward-line 1)
+ (when (not (re-search-forward rt-liber-content-regexp (point-max) t))
+ (message "no next section"))
+ (goto-char (point-at-bol)))
+
+(defun rt-liber-previous-section-in-viewer ()
+ "Move point to previous section."
+ (interactive)
+ (forward-line -1)
+ (when (not (re-search-backward rt-liber-content-regexp (point-min) t))
+ (message "no previous section"))
+ (goto-char (point-at-bol)))
+
+(defconst rt-liber-viewer-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "q") 'rt-liber-viewer-mode-quit)
+ (define-key map (kbd "n") 'rt-liber-next-section-in-viewer)
+ (define-key map (kbd "N") 'rt-liber-jump-to-latest-correspondence)
+ (define-key map (kbd "p") 'rt-liber-previous-section-in-viewer)
+ (define-key map (kbd "V") 'rt-liber-viewer-visit-in-browser)
+ (define-key map (kbd "m") 'rt-liber-viewer-answer)
+ (define-key map (kbd "M") 'rt-liber-viewer-answer-this)
+ (define-key map (kbd "t") 'rt-liber-viewer-answer-provisionally)
+ (define-key map (kbd "T") 'rt-liber-viewer-answer-provisionally-this)
+ (define-key map (kbd "F") 'rt-liber-viewer-answer-verbatim-this)
+ (define-key map (kbd "c") 'rt-liber-viewer-comment)
+ (define-key map (kbd "C") 'rt-liber-viewer-comment-this)
+ (define-key map (kbd "g") 'revert-buffer)
+ (define-key map (kbd "SPC") 'scroll-up)
+ (define-key map (kbd "DEL") 'scroll-down)
+ (define-key map (kbd "h") 'rt-liber-viewer-show-ticket-browser)
+ map)
+ "Key map for ticket viewer.")
+
+(define-derived-mode rt-liber-viewer-mode nil
+ "RT Liberation Viewer"
+ "Major Mode for viewing RT tickets.
+\\{rt-liber-viewer-mode-map}"
+ (set
+ (make-local-variable 'font-lock-defaults)
+ '((rt-liber-viewer-font-lock-keywords)))
+ (set (make-local-variable 'revert-buffer-function)
+ 'rt-liber-refresh-ticket-history)
+ (set (make-local-variable 'buffer-stale-function)
+ (lambda (&optional noconfirm) 'slow))
+ (set (make-local-variable 'auto-revert-interval)
+ (* 15 60)) ;; 15 minutes
+ (when rt-liber-jump-to-latest
+ (rt-liber-jump-to-latest-correspondence))
+ (run-hooks 'rt-liber-viewer-hook))
+
+(defun rt-liber-display-ticket-history (ticket-alist &optional assoc-browser)
+ "Display history for ticket.
+
+TICKET-ALIST alist of ticket data.
+ASSOC-BROWSER if non-nil should be a ticket browser."
+ (let* ((ticket-id (rt-liber-ticket-id-only ticket-alist))
+ (contents (rt-liber-run-ticket-history-base-query ticket-id))
+ (new-ticket-buffer (get-buffer-create
+ (concat "*RT Ticket #" ticket-id "*"))))
+ (with-current-buffer new-ticket-buffer
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (insert contents)
+ (goto-char (point-min))
+ (rt-liber-viewer-mode)
+ (set
+ (make-local-variable 'rt-liber-ticket-local)
+ ticket-alist)
+ (when assoc-browser
+ (set
+ (make-local-variable 'rt-liber-assoc-browser)
+ assoc-browser))
+ (set-buffer-modified-p nil)
+ (setq buffer-read-only t)))
+ (switch-to-buffer new-ticket-buffer)))
+
+(defun rt-liber-refresh-ticket-history (&optional ignore-auto noconfirm)
+ (interactive)
+ (if rt-liber-ticket-local
+ (rt-liber-display-ticket-history rt-liber-ticket-local
+ rt-liber-assoc-browser)
+ (error "not viewing a ticket")))
+
+;; wrapper functions around specific functions provided by a backend
+
+(defun rt-liber-viewer-answer ()
+ "Answer the ticket."
+ (interactive)
+ (cond ((featurep 'rt-liberation-gnus)
+ (rt-liber-gnus-compose-reply-to-requestor))
+ (t (error "no function defined"))))
+
+(defun rt-liber-viewer-answer-this ()
+ "Answer the ticket using the current context."
+ (interactive)
+ (cond ((featurep 'rt-liberation-gnus)
+ (rt-liber-gnus-compose-reply-to-requestor-to-this))
+ (t (error "no function defined"))))
+
+(defun rt-liber-viewer-answer-verbatim-this ()
+ "Answer the ticket using the current context verbatim."
+ (interactive)
+ (cond ((featurep 'rt-liberation-gnus)
+ (rt-liber-gnus-compose-reply-to-requestor-verbatim-this))
+ (t (error "no function defined"))))
+
+(defun rt-liber-viewer-answer-provisionally ()
+ "Provisionally answer the ticket."
+ (interactive)
+ (cond ((featurep 'rt-liberation-gnus)
+ (rt-liber-gnus-compose-provisional))
+ (t (error "no function defined"))))
+
+(defun rt-liber-viewer-answer-provisionally-this ()
+ "Provisionally answer the ticket using the current context."
+ (interactive)
+ (cond ((featurep 'rt-liberation-gnus)
+ (rt-liber-gnus-compose-provisional-to-this))
+ (t (error "no function defined"))))
+
+(defun rt-liber-viewer-comment ()
+ "Comment on the ticket."
+ (interactive)
+ (cond ((featurep 'rt-liberation-gnus)
+ (rt-liber-gnus-compose-comment))
+ (t (error "no function defined"))))
+
+(defun rt-liber-viewer-comment-this ()
+ "Comment on the ticket using the current context."
+ (interactive)
+ (cond ((featurep 'rt-liberation-gnus)
+ (rt-liber-gnus-compose-comment-this))
+ (t (error "no function defined"))))
+
+
+;;; --------------------------------------------------------
+;;; Ticket browser
+;;; --------------------------------------------------------
+
+;; accept a ticket-alist object and return an alist mapping ticket
+;; properties to format characters for use in `rt-liber-format'.
+(defun rt-liber-format-function (ticket-alist)
+ "Return a pairing of TICKET-ALIST values to %-sequences."
+ (let* ((id (cdr (assoc "id" ticket-alist)))
+ (subject (cdr (assoc "Subject" ticket-alist)))
+ (status (cdr (assoc "Status" ticket-alist)))
+ (created (cdr (assoc "Created" ticket-alist)))
+ (resolved (cdr (assoc "Resolved" ticket-alist)))
+ (requestors (cdr (assoc "Requestors" ticket-alist)))
+ (creator (cdr (assoc "Creator" ticket-alist)))
+ (owner (cdr (assoc "Owner" ticket-alist)))
+ (queue (cdr (assoc "Queue" ticket-alist)))
+ (anc (if rt-liber-anc-p
+ (rt-liber-get-ancillary-text
+ (rt-liber-ticket-id-only ticket-alist))
+ "")))
+ (list (cons ?i (or id "N/A"))
+ (cons ?s (or subject "N/A"))
+ (cons ?c (or created "N/A"))
+ (cons ?S (or status "N/A"))
+ (cons ?r (or resolved "N/A"))
+ (cons ?R (or requestors "N/A"))
+ (cons ?C (or creator "N/A"))
+ (cons ?o (or owner "N/A"))
+ (cons ?q (or queue "N/A"))
+ (cons ?A (or anc "")))))
+
+(defun rt-liber-format (format ticket-alist)
+ "Substitute %-sequences in FORMAT."
+ (let ((alist (rt-liber-format-function ticket-alist)))
+ (replace-regexp-in-string
+ "%."
+ (lambda (str)
+ (let ((char (aref str 1)))
+ (if (eq char ?%) "%"
+ (or (cdr (assoc char alist)) ""))))
+ format t t)))
+
+(defun rt-liber-ticketlist-browser-redraw-f (ticket)
+ "Display TICKET."
+ (insert (rt-liber-format "[%c] %i" ticket))
+ (add-text-properties (point-at-bol)
+ (point-at-eol)
+ '(face rt-liber-ticket-face))
+ (newline)
+ (insert (rt-liber-format " [%S] %s" ticket))
+ (let ((p (point)))
+ (insert (rt-liber-format " %A" ticket))
+ (add-text-properties p (point)
+ '(face font-lock-comment-face)))
+ (newline)
+ (insert (rt-liber-format " %o <== %R" ticket)))
+
+(defun rt-liber-ticketlist-browser-redraw (ticketlist &optional query)
+ "Display TICKETLIST. Optionally display QUERY as well."
+ (erase-buffer)
+ (when query
+ (insert (format "Query: %s" query))
+ (newline)
+ (insert (format "%d tickets" (length ticketlist)))
+ (newline))
+ (when ticketlist
+ (let ((filtered-count 0))
+ (newline 2)
+ (dolist (ticket
+ (funcall rt-liber-browser-default-sorting-function
+ ticketlist))
+ ;; skip filtered tickets, but count how many have been skipped
+ (if (funcall rt-liber-browser-default-filter-function ticket)
+ (progn
+ ;; assumes that rt-liber-ticketlist-browser-redraw-f leaves
+ ;; point at the end of the ticket drawn
+ (let ((start (point)))
+ (funcall rt-liber-custom-ticket-redraw-function ticket)
+ (add-text-properties start
+ (point)
+ (list 'rt-ticket ticket))
+ (when (and (featurep 'rt-liberation-multi)
+ (rt-liber-ticket-marked-p ticket))
+ (add-text-properties start
+ (point)
+ '(face rt-liber-marked-ticket-face))))
+ (newline))
+ (setq filtered-count (1+ filtered-count))))
+ (when (< 0 filtered-count)
+ (insert (format "%d tickets not shown (filtered)" filtered-count))))))
+
+(defun rt-liber-browser-refresh (&optional ignore-auto noconfirm)
+ (interactive)
+ (if rt-liber-query
+ (when (or rt-liber-browser-do-refresh
+ noconfirm)
+ ;; explicitly pass nil NEW to `rt-liber-browse-query'
+ (rt-liber-browse-query rt-liber-query nil))
+ (error "no buffer-local query")))
+
+(defun rt-liber-browser-refresh-and-return ()
+ (interactive)
+ (let ((id (rt-liber-browser-ticket-id-at-point)))
+ (rt-liber-browser-refresh)
+ (rt-liber-browser-move-point-to-ticket id)))
+
+;; This is just a special case of
+;; `rt-liber-browser-ticket-<PROPERTY>-at-point'
+(defun rt-liber-browser-ticket-id-at-point (&optional point)
+ "Return the ticket id for the ticket at buffer position.
+
+If POINT is nil then called on (point)."
+ (when (not point)
+ (setq point (point)))
+ (let ((value (rt-liber-ticket-id-only
+ (get-text-property point 'rt-ticket))))
+ (if value
+ value
+ (error "no such ticket property at point"))))
+
+(defun rt-liber-ticket-taken-p (ticket-alist)
+ "Return t if TICKET-ALIST is owned by Nobody."
+ (when (not ticket-alist)
+ (error "null argument"))
+ (let ((owner (cdr (assoc "Owner" ticket-alist))))
+ (if (string= owner "Nobody")
+ nil
+ t)))
+
+(defun rt-liber-next-ticket-in-browser ()
+ "Move point to the next ticket."
+ (interactive)
+ (let ((next (next-single-property-change (point) 'rt-ticket)))
+ (when next (goto-char next))))
+
+(defun rt-liber-previous-ticket-in-browser ()
+ "Move point to the previous ticket."
+ (interactive)
+ (let ((prev (previous-single-property-change (point) 'rt-ticket)))
+ (when prev (goto-char prev))))
+
+(defun rt-liber-display-ticket-at-point ()
+ "Display the contents of the ticket at point."
+ (interactive)
+ (let ((ticket-alist (get-text-property (point) 'rt-ticket)))
+ (rt-liber-display-ticket-history ticket-alist (current-buffer))))
+
+(defun rt-liber-browser-search (id)
+ "Return point where ticket with ID is displayed or nil."
+ (let ((p nil))
+ (save-excursion
+ (goto-char (point-min))
+ (let ((point-id (rt-liber-ticket-id-only
+ (get-text-property (point) 'rt-ticket))))
+ (if
+ ;; (predicate) looks for the exceptional situation
+ (and point-id (string= id point-id))
+ ;; (consequent) we're done
+ (setq p (point))
+ ;; (alternative) continue looking
+ (while (and (not p)
+ (rt-liber-next-ticket-in-browser))
+ (let ((point-id (rt-liber-ticket-id-only
+ (get-text-property (point) 'rt-ticket))))
+ (when (string= id point-id)
+ (setq p (point))))))))
+ p))
+
+(defun rt-liber-browser-move-point-to-ticket (id)
+ "Move point to the beginning of ticket with ID."
+ (let ((p (rt-liber-browser-search id)))
+ (if p
+ (progn
+ (goto-char p)
+ (recenter-top-bottom))
+ (error "ticket #%s not found" id))))
+
+;;; --------------------------------------------------------
+;;; Ticket browser sorting
+;;; --------------------------------------------------------
+
+(defun rt-liber-lex-lessthan-p (a b field)
+ "Return t if A is lexicographically less than B in FIELD."
+ (let ((field-a (cdr (assoc field a)))
+ (field-b (cdr (assoc field b))))
+ (if (and field-a field-b)
+ (string-lessp field-a field-b)
+ (error "\"%s\" is not a valid ticket field" field))))
+
+(defun rt-liber-time-lessthan-p (a b field)
+ "Return t if A is chronologically less than B in FIELD."
+ (let ((field-a (cdr (assoc field a)))
+ (field-b (cdr (assoc field b))))
+ (if (and field-a field-b)
+ (time-less-p (date-to-time field-a)
+ (date-to-time field-b))
+ (error "\"%s\" is not a valid ticket field" field))))
+
+(defun rt-liber-sort-ticket-list (ticket-list sort-f)
+ "Return a copy of TICKET-LIST sorted by SORT-F."
+ (let ((seq (copy-seq ticket-list)))
+ (sort seq sort-f)))
+
+(defun rt-liber-sort-by-owner (ticket-list)
+ "Sort TICKET-LIST lexicographically by owner."
+ (rt-liber-sort-ticket-list
+ ticket-list
+ #'(lambda (a b)
+ (rt-liber-lex-lessthan-p a b "Owner"))))
+
+(defun rt-liber-sort-by-time-created (ticket-list)
+ "Sort TICKET-LIST in reverse chronological order."
+ (reverse
+ (rt-liber-sort-ticket-list
+ ticket-list
+ #'(lambda (a b)
+ (rt-liber-time-lessthan-p a b "Created")))))
+
+;;; --------------------------------------------------------
+;;; Ticket browser filtering
+;;; --------------------------------------------------------
+
+;; See the fine manual for example code.
+
+(defun rt-liber-default-filter-f (ticket)
+ "The default filtering function for the ticket browser
+
+This function is really a placeholder for user custom functions,
+and as such always return t."
+ t)
+
+;;; --------------------------------------------------------
+;;; Version comparison functions
+;;; --------------------------------------------------------
+
+;; rt-liber-version-<: string * string -> t-or-nil
+(defun rt-liber-version-< (vnum1 vnum2)
+ "Test whehther version number VNUM1 is less than VNUM2.
+Arguments must be strings Lisp objects, and not numbers.
+
+Examples:
+ (rt-liber-version-< \"1.01\" \"1.11\")
+ => t
+
+ (rt-liber-version-< \"1.1\" \"1.0.1\")
+ => nil"
+ (rt-liber-version-<- (rt-liber-version-value
+ (rt-liber-version-read vnum1))
+ (rt-liber-version-value
+ (rt-liber-version-read vnum2))))
+
+;; rt-liber-version-read: string -> list string
+(defun rt-liber-version-read (str)
+ "Tokenize version number STR whenever the syntax class changes.
+
+ Example:
+ \"1.043.0-1_=+\" \
+==> (\"1\" \".\" \"043\" \".\" \"0\" \"-\" \"1\" \"_=+\")"
+ (let ((tokens nil)
+ (start 0)
+ (re (mapconcat 'identity '("[[:digit:]]+" "[[:punct:]]+") "\\|")))
+ (while (and (string-match re (substring str start))
+ (> (length str) start))
+ (setq tokens (cons (match-string 0 (substring str start)) tokens))
+ (setq start (+ start (match-end 0))))
+ (if (< start (length str))
+ (error "Unknown character: %s" (substring str start (1+ start))))
+ (reverse tokens)))
+
+;; rt-liber-version-value: list string -> list number
+(defun rt-liber-version-value (tokens)
+ "Convert list of TOKENS to a comparable number list."
+ (mapcar #'(lambda (tk)
+ (if (string-match "^0+$" tk)
+ 1
+ (if (string-match "^[[:digit:]]+$" tk)
+ (if (string-match "^0+" tk)
+ (1+ (* (string-to-number tk)
+ (expt 10
+ (- (length
+ (match-string 0 tk))))))
+ (1+ (string-to-number tk)))
+ (if (string-match "^[[:punct:]]+$" tk)
+ 0
+ ;; else (string-match "[^[:digit:][:punct:]]" tk)
+ -1))))
+ tokens))
+
+;; rt-liber-version-<-: list number -> t-or-nil
+(defun rt-liber-version-<- (vals1 vals2)
+ "Test whether version representation VALS1 is less than VALS2."
+ (if (and (null vals1) (null vals2))
+ nil
+ (if (null vals2)
+ nil
+ (if (null vals1)
+ t
+ (if (= (car vals1) (car vals2))
+ (rt-liber-version-<- (cdr vals1) (cdr vals2))
+ (if (< (car vals1) (car vals2))
+ t
+ nil))))))
+
+
+;;; --------------------------------------------------------
+;;; Entry points
+;;; --------------------------------------------------------
+
+(defun rt-liber-browse-query (query &optional new)
+ "Run QUERY against the server and launch the browser.
+
+NEW if non-nil create additional browser buffer. If NEW is a
+string then that will be the name of the new buffer."
+ (interactive "Mquery: ")
+ (condition-case excep
+ (rt-liber-browser-startup
+ (rt-liber-run-show-base-query
+ (rt-liber-run-ls-query query))
+ query new)
+ (rt-liber-no-result-from-query-error
+ (rt-liber-browser-with-message "no results from query"
+ query new))))
+
+
+;;; --------------------------------------------------------
+;;; Major mode definitions
+;;; --------------------------------------------------------
+
+(defun rt-liber-multi-delete-spam ()
+ "Delete marked tickets as spam."
+ (interactive)
+ (cond ((featurep 'rt-liberation-multi)
+ (when (y-or-n-p "Delete marked tickets as spam? ")
+ (rt-liber-multi-flag-as-spam-and-delete)))
+ (t (error "rt-liberation-multi isn't loaded"))))
+
+(defun rt-liber-browser-mode-quit ()
+ "Bury the ticket browser."
+ (interactive)
+ (bury-buffer))
+
+(defconst rt-liber-browser-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "q") 'rt-liber-browser-mode-quit)
+ (define-key map (kbd "n") 'rt-liber-next-ticket-in-browser)
+ (define-key map (kbd "p") 'rt-liber-previous-ticket-in-browser)
+ (define-key map (kbd "RET") 'rt-liber-display-ticket-at-point)
+ (define-key map (kbd "g") 'revert-buffer)
+ (define-key map (kbd "G") 'rt-liber-browser-refresh-and-return)
+ (define-key map (kbd "s") 'rt-liber-browser-mark-as-spam)
+ (define-key map (kbd "S") 'rt-liber-multi-delete-spam)
+ (define-key map (kbd "a") 'rt-liber-browser-assign)
+ (define-key map (kbd "r") 'rt-liber-browser-resolve)
+ (define-key map (kbd "o") 'rt-liber-browser-open)
+ (define-key map (kbd "t") 'rt-liber-browser-take-ticket-at-point)
+ (define-key map (kbd "A") 'rt-liber-browser-ancillary-text)
+ (define-key map (kbd "SPC") 'scroll-up)
+ (define-key map (kbd "DEL") 'scroll-down)
+ (define-key map (kbd "m") 'rt-liber-browser-move)
+ (define-key map (kbd "M") 'rt-liber-mark-ticket-at-point)
+ map)
+ "Key map for ticket browser.")
+
+(define-derived-mode rt-liber-browser-mode nil
+ "RT Liberation Browser"
+ "Major Mode for browsing RT tickets.
+\\{rt-liber-browser-mode-map}"
+ (set (make-local-variable 'revert-buffer-function)
+ 'rt-liber-browser-refresh)
+ (set (make-local-variable 'buffer-stale-function)
+ (lambda (&optional noconfirm) 'slow))
+ (set (make-local-variable 'auto-revert-interval)
+ (* 15 60)) ;; 15 minutes
+ (run-hooks 'rt-liber-browser-hook))
+
+(defun rt-liber-setup-browser-name (new)
+ (setq rt-liber-browser-buffer
+ (get-buffer-create
+ (if new
+ (generate-new-buffer-name
+ (if (stringp new)
+ new
+ rt-liber-browser-buffer-name))
+ (if (and (boundp 'rt-liber-query)
+ rt-liber-query)
+ (buffer-name)
+ rt-liber-browser-buffer-name)))))
+
+(defun rt-liber-browser-with-message (message &optional query new)
+ "Start the RT ticket browser and display MESSAGE."
+ (interactive)
+ (rt-liber-setup-browser-name new)
+ ;; setup stage (invisible to user)
+ (with-current-buffer rt-liber-browser-buffer
+ (let ((inhibit-read-only t))
+ (goto-char (point-min))
+ (rt-liber-ticketlist-browser-redraw nil query)
+ (newline 2)
+ (insert message)
+ (set (make-local-variable 'rt-liber-query) query)))
+ ;; display stage (user can see updates)
+ (switch-to-buffer rt-liber-browser-buffer)
+ (setq buffer-read-only t))
+
+(defun rt-liber-browser-startup (ticket-list &optional query new)
+ "Start the RT ticket browser."
+ (interactive)
+ (rt-liber-setup-browser-name new)
+ ;; setup stage (invisible to user)
+ (with-current-buffer rt-liber-browser-buffer
+ (let ((inhibit-read-only t))
+ (rt-liber-ticketlist-browser-redraw ticket-list query)
+ (goto-char (point-min))
+ (rt-liber-next-ticket-in-browser)
+ (rt-liber-browser-mode)
+ ;; store the ticket-list and the query which produced the buffer
+ ;; as buffer local variables
+ (set (make-local-variable 'rt-liber-ticket-list) ticket-list)
+ (set (make-local-variable 'rt-liber-query) query)))
+ ;; display stage (user can see updates)
+ (switch-to-buffer rt-liber-browser-buffer)
+ (setq buffer-read-only t))
+
+(defun rt-liber-browser-ancillary-text ()
+ "Wrapper function around storage backend."
+ (interactive)
+ (when (not (featurep 'rt-liberation-storage))
+ (error "rt-liberation-storage isn't loaded"))
+ (let ((initial-contents ""))
+ (rt-liber-set-ancillary-text
+ (read-from-minibuffer "Text: " initial-contents))))
+
+;;; --------------------------------------------------------
+;;; Command module
+;;; --------------------------------------------------------
+
+;; when this module is stable enough it should be documented in the
+;; manual -- yrk
+
+(defun rt-liber-command-get-dictionary-value (sym dic)
+ "Utility function for retrieving alist values."
+ (let ((value (cdr (assoc sym dic))))
+ (if value
+ value
+ (error "%s not a key in dictionary %s" sym dic))))
+
+(defun rt-liber-command-get-command-string (command-symbol)
+ "Return value associated with key COMMAND-SYMBOL."
+ (rt-liber-command-get-dictionary-value
+ command-symbol
+ rt-liber-command-dictionary))
+
+(defun rt-liber-command-get-status-string (status-symbol)
+ "Return value associated with key STATUS-SYMBOL."
+ (rt-liber-command-get-dictionary-value
+ status-symbol
+ rt-liber-status-dictionary))
+
+(defun rt-liber-command-get-custom-field-string (custom-field-symbol)
+ "Return value associated with key CUSTOM-FIELD-SYMBOL."
+ (rt-liber-command-get-dictionary-value
+ custom-field-symbol
+ rt-liber-custom-field-dictionary))
+
+(defun rt-liber-command-runner (op arg-string)
+ "Run OP command against the server with ARG-STRING."
+ (message "started '%s' command at %s..." op (current-time-string))
+ (condition-case excep
+ (with-temp-buffer
+ (call-process-shell-command rt-liber-rt-binary nil t nil
+ op arg-string)
+ (message "command ended at %s" (current-time-string))
+ (buffer-string))
+ (file-error
+ (error "could not find the RT binary at: %s" rt-liber-rt-binary))
+ (error "an unhandled exception occured: %s" excep)))
+
+;; the user might not see this but at the very least it will leave a
+;; trace in the *Messages* buffer -- yrk
+(defun rt-liber-command-runner-parser-f ()
+ "Display command return status from the server to the user."
+ (message (buffer-string)))
+
+(defun rt-liber-command-set-cf (id field value)
+ "Add custom field FIELD with VALUE to ID.
+If FIELD already exists, update to VALUE."
+ ;; TODO: This may not work with standard rt cli.
+ ;;
+ ;; works fine with the stock version 3.8.2 -- yrk
+
+ ;; TODO: Should probably bust comment out to its own function.
+ (let ((command (rt-liber-command-get-command-string 'comment))
+ (args
+ (format "-f %s=%s ticket/%s" field value id)))
+ (rt-liber-parse-answer
+ (rt-liber-command-runner command args)
+ 'rt-liber-command-runner-parser-f)))
+
+(defun rt-liber-command-set-status (id status)
+ "Set ticket ID status to be STATUS."
+ ;; TODO: Sanity check status
+ ;; TODO: defmacro?
+ (let ((command (rt-liber-command-get-command-string 'edit))
+ (args
+ (format "ticket/%s set status=%s" id status)))
+ (rt-liber-parse-answer
+ (rt-liber-command-runner command args)
+ 'rt-liber-command-runner-parser-f)))
+
+(defun rt-liber-command-set-status-deleted (id)
+ "Set the status of ticket ID to `deleted'."
+ (rt-liber-command-set-status
+ id (rt-liber-command-get-status-string 'deleted)))
+
+(defun rt-liber-command-set-status-resolved (id)
+ "Set the status of ticket ID to `resolved'."
+ (rt-liber-command-set-status
+ id (rt-liber-command-get-status-string 'resolved)))
+
+(defun rt-liber-command-set-status-open (id)
+ "Set the status of ticket ID to `open'."
+ (rt-liber-command-set-status
+ id (rt-liber-command-get-status-string 'open)))
+
+(defun rt-liber-command-set-owner (id owner)
+ "Set the owner of ticket ID to OWNER."
+ (let ((command (rt-liber-command-get-command-string 'edit))
+ (args
+ (format "ticket/%s set owner=%s" id owner)))
+ (rt-liber-parse-answer
+ (rt-liber-command-runner command args)
+ 'rt-liber-command-runner-parser-f)))
+
+(defun rt-liber-command-set-queue (id queue)
+ "Set the queue of ticket ID to QUEUE."
+ (let ((command (rt-liber-command-get-command-string 'edit))
+ (args
+ (format "ticket/%s set queue=%s" id queue)))
+ (rt-liber-parse-answer
+ (rt-liber-command-runner command args)
+ 'rt-liber-command-runner-parser-f)))
+
+(defun rt-liber-browser-assign (name)
+ "Assign current ticket to a user NAME."
+ (interactive "sAssign to: ")
+ (let ((taken-p (rt-liber-ticket-taken-p
+ (get-text-property (point) 'rt-ticket))))
+ (when (or (not taken-p)
+ (and taken-p
+ (y-or-n-p "Ticket already assigned! Are you sure?")))
+ (rt-liber-command-set-owner
+ (rt-liber-browser-ticket-id-at-point)
+ name)
+ (rt-liber-browser-refresh-and-return))))
+
+(defun rt-liber-browser-resolve ()
+ "Resolve the current ticket."
+ (interactive)
+ (rt-liber-command-set-status-resolved
+ (rt-liber-browser-ticket-id-at-point))
+ (rt-liber-browser-refresh-and-return))
+
+(defun rt-liber-browser-open ()
+ "Open the current ticket."
+ (interactive)
+ (rt-liber-command-set-status-open
+ (rt-liber-browser-ticket-id-at-point))
+ (rt-liber-browser-refresh-and-return))
+
+(defun rt-liber-browser-move (queue)
+ "Move the current ticket to a different queue."
+ (interactive "sQueue: ")
+ (rt-liber-command-set-queue
+ (rt-liber-browser-ticket-id-at-point)
+ queue)
+ (rt-liber-browser-refresh))
+
+(defun rt-liber-browser-mark-as-spam ()
+ "Mark the current ticket as spam, and delete it."
+ (interactive)
+ (if (y-or-n-p "Delete marked ticket as spam? ")
+ (let ((id (rt-liber-browser-ticket-id-at-point)))
+ (rt-liber-command-set-cf
+ id (rt-liber-command-get-custom-field-string 'cf-is-spam) "yes")
+ (rt-liber-command-set-status-deleted id)
+ (rt-liber-browser-refresh))
+ (message "aborted")))
+
+(defun rt-liber-browser-take-ticket-at-point ()
+ "Assign the ticket under point to `rt-liber-username'."
+ (interactive)
+ (when (not rt-liber-username)
+ (error "`rt-liber-username' is nil"))
+ (let ((taken-p (rt-liber-ticket-taken-p
+ (get-text-property (point) 'rt-ticket))))
+ (when (or (not taken-p)
+ (and taken-p
+ (y-or-n-p "Ticket already taken! Are you sure?")))
+ (rt-liber-command-set-owner
+ (rt-liber-browser-ticket-id-at-point)
+ rt-liber-username)
+ (rt-liber-browser-refresh))))
+
+(defun rt-liber-viewer-take-ticket ()
+ "Assign the current ticket to `rt-liber-username'."
+ (interactive)
+ (when (not rt-liber-username)
+ (error "`rt-liber-username' is nil"))
+ (let ((id (rt-liber-ticket-id-only rt-liber-ticket-local))
+ (taken-p (rt-liber-ticket-taken-p rt-liber-ticket-local)))
+ (if id
+ (progn
+ (when (or (not taken-p)
+ (and taken-p
+ (y-or-n-p "Ticket already taken! Are you sure?")))
+ (rt-liber-command-set-owner id rt-liber-username)
+ (rt-liber-refresh-ticket-history)))
+ (error "no ticket currently in view"))))
+
+(provide 'rt-liberation)
+
+;;; rt-liberation.el ends here.