packages feed

twidge (empty) → 0.99.0

raw patch · 25 files changed

+3495/−0 lines, 25 filesdep +Cabaldep +ConfigFiledep +HSHsetup-changed

Dependencies added: Cabal, ConfigFile, HSH, HaXml, MissingH, base, directory, hslogger, mtl, network, parsec, regex-posix, unix

Files

+ COPYING view
@@ -0,0 +1,340 @@+		    GNU GENERAL PUBLIC LICENSE+		       Version 2, June 1991++ Copyright (C) 1989, 1991 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.++			    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 Library 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 St, 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 Library General+Public License instead of this License.
@@ -0,0 +1,26 @@+Copyright (C) 2006-2008 John Goerzen <jgoerzen@complete.org>++All code, documentation, and build scripts are under the following+license unless otherwise noted:++   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 St, Fifth Floor, Boston, MA  02110-1301  USA++The GNU General Public License is available in the file COPYING in the source+distribution.  Debian GNU/Linux users may find this in+/usr/share/common-licenses/GPL-2.++If the GPL is unacceptable for your uses, please e-mail me; alternative+terms can be negotiated for your project.+
+ Commands.hs view
@@ -0,0 +1,70 @@+{-+Copyright (C) 2006-2008 John Goerzen <jgoerzen@complete.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+-}++{- |+   Module     : Commands+   Copyright  : Copyright (C) 2006-2008 John Goerzen+   License    : GNU GPL, version 2 or above++   Maintainer : John Goerzen <jgoerzen@complete.org>+   Stability  : provisional+   Portability: portable++Written by John Goerzen, jgoerzen\@complete.org++-}+module Commands where++import Text.Printf+import Utils+import Types+import Config++import qualified Commands.Follow+import qualified Commands.Ls+import qualified Commands.Setup+import qualified Commands.Update++--allCommands :: [(String, Command)]+allCommands = +    [Commands.Update.dmsend,+     Commands.Follow.follow,+     Commands.Ls.lsarchive,+     lscommands,+     Commands.Ls.lsdm,+     Commands.Ls.lsdmarchive,+     Commands.Ls.lsfollowers,+     Commands.Ls.lsfollowing,+     Commands.Ls.lsrecent,+     Commands.Ls.lsreplies,+     Commands.Setup.setup,+     Commands.Follow.unfollow,+     Commands.Update.update+    ]++lscommands = +    simpleCmd "lscommands" "Display a list of all available commands" ""+                  [] lscommands_worker++lscommands_worker _ _ _ =+    do putStrLn "All available commands:"+       printf "%-20s %s\n" "Name" "Description"+       putStrLn "-------------------- -------------------------------------------------------"+       mapM_ (\(_, x) -> printf "%-20s %s\n" (cmdname x) (cmddescrip x))+             allCommands+                 
+ Commands/Ls.hs view
@@ -0,0 +1,342 @@+{-+Copyright (C) 2006-2008 John Goerzen <jgoerzen@complete.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+-}++module Commands.Ls(lsrecent, lsreplies, lsfollowing, lsfollowers, lsarchive, lsdm, lsdmarchive) where+import Utils+import System.Log.Logger+import Types+import Text.Printf+import System.Console.GetOpt+import Data.List+import Text.XML.HaXml hiding (when)+import Download+import FeedParser+import Data.ConfigFile+import Data.String.Utils(strip)+import Config+import Data.Either.Utils(forceEither)+import Control.Monad(when)+import Distribution.Simple.Utils(wrapText)+import HSH+import System.Console.GetOpt.Utils++i = infoM "ls"++stdopts = [Option "a" ["all"] (NoArg ("a", "")) +                      "Show ALL results, not just 1st page\n\+                      \WARNING: may generate excessive traffic.  \+                      \Use with caution!",+           Option "l" ["long"] (NoArg ("l", "")) +                      "Long format output -- more info and \+                      \tab-separated columns"]++sinceopts = [+           Option "e" ["exec"] (ReqArg (stdRequired "e") "COMMAND")+                  "Suppress normal output, and instead call COMMAND\n\+                  \once for each output item.  The command will be\n\+                  \passed exactly four arguments: update ID,\n\+                  \username, suggested Message-ID, and update\n\+                  \content.  These arguments may contain shell\n\+                  \metacharacters.",+           Option "m" ["mailto"] (ReqArg (stdRequired "m") "ADDRESS")+                  "Suppress normal output, and instead generate an\n\+                  \email with the data and send it to ADDRESS.",+           Option "s" ["saveid"] (NoArg ("s", ""))+                      "Save topmost ID for future use with --unseen.\n\+                      \Will write the ID to your config file.",+           Option "u" ["unseen"] (NoArg ("u", ""))+                      "Show only items since the last use of --saveid"]++paginated workerfunc cppath cp (args, remainder)+    | lookup "a" args == Nothing = +        do workerfunc cppath cp (args, remainder) 1+           return ()+    | otherwise = paginateloop 1+    where paginateloop page =+              do r <- workerfunc cppath cp (args, remainder) page+                 if null r+                     then return ()+                     else paginateloop (page + 1)++maybeSaveList section cpath cp args [] = return ()+maybeSaveList section cpath cp args newids =+    do debugM section $ "maybeSaveList called: " ++ show args ++ " " ++ show newids+       maybeSave section cpath cp args theid+    where theid = maximum . map (read::String -> Integer) $ newids++maybeSave section cpath cp args newid =+    case (lookup "s" args, get cp section "lastid") of+      (Nothing, _) -> return ()+      (_, Left _) -> saveid+      (_, Right x) ->+          if (read x) < (newid::Integer)+             then return ()+             else saveid+    where saveid = writeCP cpath newcp+          newcp = forceEither $+                  do cp2 <- if (has_section cp section)+                                then return cp+                                else add_section cp section+                     cp2 <- set cp2 section "lastid" (show newid)+                     return cp2++sinceArgs section cp args =+    case (lookup "u" args, get cp section "lastid") of+      (Nothing, _) -> []+      (_, Left _) -> []+      (_, Right a) -> +          [("since_id", strip a)]++--------------------------------------------------+-- lsrecent+--------------------------------------------------++lsrecent = simpleCmd "lsrecent" "List recent updates from those you follow"+             lsrecent_help+             (stdopts ++ sinceopts) (paginated (statuses_worker "lsrecent"+                                                "/statuses/friends_timeline"))++lsreplies = simpleCmd "lsreplies" "List recent replies to you"+            lsreplies_help+            (stdopts ++ sinceopts) (paginated (statuses_worker "lsreplies" +                                               "/statuses/replies"))++lsarchive = simpleCmd "lsarchive" "List recent status updates you posted yourself"+            lsarchive_help+            (stdopts ++ sinceopts) (paginated (statuses_worker "lsarchive"+                                               "/statuses/user_timeline"))++lsdm = simpleCmd "lsdm" "List recent direct messages to you"+       lsdm_help+       (stdopts ++ sinceopts) (paginated (dm_worker "lsdm" +                                          "/direct_messages"))++lsdmarchive = simpleCmd "lsdmarchive" "List recent direct messages you sent"+              lsdmarchive_help+              (stdopts ++ sinceopts) (paginated (dm_worker "lsdmarchive"+                                                 "/direct_messages/sent"))++statuses_worker = generic_worker handleStatus+dm_worker = generic_worker handleDM++generic_worker procfunc section command cpath cp (args, _) page =+    do xmlstr <- sendAuthRequest cp (command ++ ".xml")+                 (("page", show page) : sinceArgs section cp args)+                 []+       debugM section $ "Got doc: " ++ xmlstr+       results <- procfunc section cp args xmlstr+       when (page == 1) $+            maybeSaveList section cpath cp args (map sId results)+       return results++lsrecent_help =+ "Usage: twidge lsrecent [options]\n\n\+ \You can see the 20 most recent items from your friends with:\n\n\+ \   twidge lsrecent\n\n\+ \To see items that you haven't seen yet, and remember this for the future,\n\+ \use:\n\n\+ \   twidge lsrecent -su\n\n\+ \After running that once, you may want to use -asu in the future to get all\n\+ \unseen messages, even if there are more than 20.  Don't use -a until\n\+ \you've used -s at least once.\n"++lsreplies_help =+ "Usage: twidge lsreplies [options]\n\n\+ \You can see the 20 most recent @replies from others to you with:\n\n\+ \   twidge lsreplies\n\n\+ \For more examples, including how to see only unseen replies, please\n\+ \refer to the examples under twidge lsrecent --help, which also pertain\n\+ \to lsreplies.\n"++lsarchive_help =+ "Usage: twidge lsarchive [options]\n\n\+ \You can see the 20 most recent updates you posted with:\n\n\+ \   twidge lsarchive\n\n\+ \For more examples, including how to see only unseen updates, please\n\+ \refer to the examples under twidge lsrecent --help, which also pertain\n\+ \to lsarchive.\n"++lsdm_help =+ "Usage: twidge lsdm [options]\n\n\+ \You can see the 20 most recent direct messages to you with:\n\n\+ \   twidge lsdm\n\n\+ \For more examples, including how to see only unseen updates, please\n\+ \refer to the examples under twidge lsrecent --help, which also pertain\n\+ \to lsdm.\n"+ +lsdmarchive_help =+ "Usage: twidge lsdmarchive [options]\n\n\+ \You can see the 20 most recent direct messages you sent with:\n\n\+ \   twidge lsdmarchive\n\n\+ \For more examples, including how to see only unseen updates, please\n\+ \refer to the examples under twidge lsrecent --help, which also pertain\n\+ \to lsdmarchive.\n"++handleStatus = handleGeneric (map procStatuses . getStatuses) printStatus+handleDM = handleGeneric (map procDM . getDMs) printDM++handleGeneric pfunc printfunc section cp args xmlstr = +    let doc = getContent . xmlParse section . stripUnicodeBOM $ xmlstr+        statuses = pfunc doc+    in do mapM_ (printfunc section cp args) statuses+          return statuses++procStatuses :: Content -> Message+procStatuses item = +    Message {sId = s (tag "id") item,+             sSender = s (tag "user" /> tag "screen_name") item,+             sRecipient = "",+             sText = s (tag "text") item,+             sDate = s (tag "created_at") item}++s f item = sanitize $ contentToString (keep /> f /> txt $ item)++procDM :: Content -> Message+procDM item =+    Message {sId = s (tag "id") item,+             sSender = s (tag "sender_screen_name") item,+             sRecipient = s (tag "recipient_screen_name") item,+             sText = s (tag "text") item,+             sDate = s (tag "created_at") item}++getStatuses = tag "statuses" /> tag "status"+getDMs = tag "direct-messages" /> tag "direct_message"++longStatus :: Message -> String+longStatus m = printf "%s\t%s\t%s\t%s\t%s\t\n"+               (sId m) (sSender m) (sRecipient m) (sText m) (sDate m)+shortStatus :: Message -> String+shortStatus m = +    (printf "%-22s %s\n" ("<" ++ sSender m ++ ">")+               (head wrappedtext)) +++    concatMap (printf "%-22s %s\n" "") (tail wrappedtext)+    where wrappedtext = wrapText (80 - 22 - 2) (words (sText m))++shortDM :: Message -> String+shortDM m =+     (printf "%-22s %-22s %s\n" ("<" ++ sSender m ++ ">")+                                 ("<" ++ sRecipient m ++ ">")+                                 (head wrappedtext)) +++     concatMap (printf "%-22s %-22s %s\n" "" "") (tail wrappedtext)+     where wrappedtext = wrapText (80 - 22 - 22 - 3) (words (sText m))++printStatus section cp args m = +    printGeneric shortStatus longStatus section cp args m++printDM section cp args m =+    printGeneric shortDM longStatus section cp args m++printGeneric shortfunc longfunc section cp args m =+    case (lookup "m" args) of+      Nothing -> +          case (lookup "e" args, lookup "l" args) of+            (Just cmd, _) ->+                runIO $ (cmd, [sId m, sSender m, sRecipient m, +                               sText m, sDate m])+            (Nothing, Nothing) -> putStr (shortfunc m)+            (Nothing, Just _) -> putStr (longfunc m)+      Just recipient -> mailto section cp args m recipient+    where msgid = genMsgId section m cp++mailto section cp args m recipient =+    runIO $ echo (message ++ "\n") -|- (sendmail, ["-t"])+    where sendmail = (forceEither $ get cp section "sendmail")::String+          msgid = genMsgId section m cp+          subject = take 30 (sText m) ++ "... (twidge " ++ section ++ ")"+          message = unlines $ +                    (case get cp section "mailfrom" of+                      Left _ -> ["Subject: " ++ (sSender m) ++ ": " ++ subject]+                      Right x -> ["From: " ++ (sSender m) ++ " <" ++ x ++ ">",+                                  "Subject: " ++ subject]+                    ) ++ +                    ["Message-ID: " ++ msgid,+                     "X-Twidge-urlbase: " ++ forceEither (get cp "DEFAULT" "urlbase"),+                     "X-Twidge-server-base: " ++ serverHost cp,+                     "X-Twidge-command: " ++ section,+                     "X-Twidge-update-id: " ++ sId m,+                     "X-Twidge-update-sender: " ++ sSender m,+                     "X-Twidge-update-recipient: " ++ sRecipient m,+                     "To: " ++ recipient,+                     "",+                     sText m,+                     "",+                     "(from " ++ sSender m ++ ")"]++--------------------------------------------------+-- lsfollowing+--------------------------------------------------++lsfollowing = simpleCmd "lsfollowing" "List people you are following"+             lsfollowing_help+             stdopts (paginated lsfollowing_worker)++lsfollowing_worker _ cp (args, user) page =+    do xmlstr <- sendAuthRequest cp url [("page", show page)] []+       debugM "lsfollowing" $ "Got doc: " ++ xmlstr+       let doc = getContent . xmlParse "lsfollowing" . stripUnicodeBOM $ xmlstr+       let users = map procUsers . getUsers $ doc+       mapM_ (printUser args) users+       return users+       +    where url = case user of+                  [] -> "/statuses/friends.xml"+                  [x] -> "/statuses/friends/" ++ x ++ ".xml"+                  _ -> error "Invalid args to lsfollowing; see twidge lsfollowing --help"++printUser args (name, userid) = +    case lookup "l" args of+      Nothing -> putStrLn name+      Just _ -> printf "%s\t%s\n" userid name++getUsers = tag "users" /> tag "user"++procUsers :: Content -> (String, String)+procUsers item =+    (sanitize $ contentToString (keep /> tag "screen_name" /> txt $ item),+     sanitize $ contentToString (keep /> tag "id" /> txt $ item))++lsfollowing_help =+ "Usage: twidge lsfollowing [options] [username]\n\n\+ \If username is given, list the twitter accounts that user is following.\n\+ \Otherwise, list the twitter accounts your user is following.\n"++--------------------------------------------------+-- lsfollowers+--------------------------------------------------++lsfollowers = simpleCmd "lsfollowers" "List people that follow you"+             lsfollowers_help+             stdopts (paginated lsfollowers_worker)++lsfollowers_worker _ cp (args, user) page =+    do xmlstr <- sendAuthRequest cp url [("page", show page)] []+       debugM "lsfollowers" $ "Got doc: " ++ xmlstr+       let doc = getContent . xmlParse "lsfollowers" . stripUnicodeBOM $ xmlstr+       let users = map procUsers . getUsers $ doc+       mapM_ (printUser args) users+       return users+       +    where url = case user of+                  [] -> "/statuses/followers.xml"+                  [x] -> "/statuses/followers/" ++ x ++ ".xml"+                  _ -> error "Invalid args to lsfollowers; see twidge lsfollowers --help"++lsfollowers_help =+ "Usage: twidge lsfollowers [options] [username]\n\n\+ \If username is given, list the twitter accounts that follow the user.\n\+ \Otherwise, list the twitter accounts that follow you.\n"
+ Config.hs view
@@ -0,0 +1,79 @@+{- hpodder component+Copyright (C) 2006-2008 John Goerzen <jgoerzen@complete.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+-}++{- |+   Module     : Config+   Copyright  : Copyright (C) 2006-2008 John Goerzen+   License    : GNU GPL, version 2 or above++   Maintainer : John Goerzen <jgoerzen@complete.org>+   Stability  : provisional+   Portability: portable++Written by John Goerzen, jgoerzen\@complete.org++-}+module Config where++import System.Directory+import Data.ConfigFile+import Control.Monad+import Data.Either.Utils+import Data.String.Utils(strip, split)+import System.Posix.Files(rename)++getDefaultCP =+    do return $ forceEither $ +              do cp <- set startingcp "DEFAULT" "urlbase" "https://twitter.com"+                 cp <- set cp "DEFAULT" "sendmail" "/usr/sbin/sendmail"+                 cp <- set cp "DEFAULT" "shortenurls" "yes"+                 return cp++startingcp = emptyCP {accessfunc = interpolatingAccess 10}++getCPName =+    do appdir <- getUserDocumentsDirectory+       return $ appdir ++ "/.twidgerc"++loadCP cpgiven = +    do cpname <- case cpgiven of+                   Nothing -> getCPName+                   Just x -> return x+       defaultcp <- getDefaultCP+       dfe <- doesFileExist cpname+       if dfe+          then do cp <- readfile defaultcp cpname+                  return $ forceEither cp+          else do fail $ "No config file found at " ++ cpname ++ +                           "\nRun twidge setup to configure twidge for use."++writeCP cpgiven cp =+    do cpname <- case cpgiven of+                   Nothing -> getCPName+                   Just x -> return x+       let tempname = cpname ++ ".write.tmp"+       writeFile tempname (to_string cp)+       rename tempname cpname++getList :: ConfigParser -> String -> String -> Maybe [String]+getList cp sect key = +       case get cp sect key of+         Right x -> Just (splitit x)+         Left _ -> Nothing+    where splitit x = filter (/= "") . map strip . split "," $ x+  
+ Download.hs view
@@ -0,0 +1,76 @@+{- hpodder component+Copyright (C) 2006-2007 John Goerzen <jgoerzen@complete.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+-}++{- |+   Module     : Download+   Copyright  : Copyright (C) 2006-2008 John Goerzen+   License    : GNU GPL, version 2 or above++   Maintainer : John Goerzen <jgoerzen@complete.org>+   Stability  : provisional+   Portability: portable++Written by John Goerzen, jgoerzen\@complete.org++-}++module Download(sendAuthRequest, simpleDownload) where+import System.Log.Logger+import Data.ConfigFile+import HSH+import Data.Either.Utils(forceEither)+import Network.URI+import Data.List+import Control.Exception(evaluate)++d = debugM "download"+i = infoM "download"++curl = "curl"+curlopts = ["-A", "twidge v1.0.0; Haskell; GHC", -- Set User-Agent+            "-s",               -- Silent mode+            "-S",               -- Still show error messages+            "-L",               -- Follow redirects+            "-y", "60", "-Y", "1", -- Timeouts+            "--retry", "2",     -- Retry twice+            "-f"                -- Fail on server errors+           ]++simpleDownload :: String -> IO String+simpleDownload url = run (curl, curlopts ++ [url])++sendAuthRequest :: ConfigParser -> String -> [(String, String)] -> [(String, String)] -> IO String+sendAuthRequest cp url getopts postoptlist =+    do -- Force this to be evaluated in the parent process+       authopts <- evaluate (getAuthOpts cp)+       run (curl, curlopts ++ authopts ++ postopts ++ [urlbase ++ url ++ optstr])+    where urlbase = forceEither $ get cp "DEFAULT" "urlbase"+          optstr = case getopts of+                     [] -> ""+                     _ -> "?" ++ (concat . intersperse "&" . map conv $ getopts)+          conv (k, v) = k ++ "=" ++ escapeURIString isUnreserved v+          postopts = concatMap postopt postoptlist+          postopt (k, v) = ["-d", escapeURIString isUnreserved k ++ "=" +++                                  escapeURIString isUnreserved v]++getAuthOpts :: ConfigParser -> [String]+getAuthOpts cp =+    case (get cp "DEFAULT" "username", get cp "DEFAULT" "password") of+      (Right user, Right pass) ->+          ["--user", user ++ ":" ++ pass]+      _ -> error "Missing username or password option in config file"
+ FeedParser.hs view
@@ -0,0 +1,70 @@+{- +Copyright (C) 2006-2008 John Goerzen <jgoerzen@complete.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+-}++{- |+   Module     : FeedParser+   Copyright  : Copyright (C) 2006-2008 John Goerzen+   License    : GNU GPL, version 2 or above++   Maintainer : John Goerzen <jgoerzen@complete.org>+   Stability  : provisional+   Portability: portable++Written by John Goerzen, jgoerzen\@complete.org++-}+module FeedParser where++import Text.XML.HaXml+import Data.Char+import Data.List+import Data.String.Utils(strip)++{- | Convert [Content] to a printable string, taking care to unescape it.++An implementation without unescaping would simply be:++> contentToString = concatMap (show . content)++Because HaXml's unescaping only works on Elements, we must make sure that+whatever Content we have is wrapped in an Element, then use txt to+pull the insides back out. -}+contentToString :: [Content] -> String+contentToString = +    concatMap procContent+    where procContent x = +              verbatim $ keep /> txt $ CElem (unesc (fakeElem x))++          fakeElem :: Content -> Element+          fakeElem x = Elem "fake" [] [x]++          unesc :: Element -> Element+          unesc = xmlUnEscape stdXmlEscaper++stripUnicodeBOM :: String -> String+stripUnicodeBOM ('\xef':'\xbb':'\xbf':x) = x+stripUnicodeBOM x = x++{- | Removes potentially problematic or malicious stuff -}+sanitize :: String -> String+sanitize = strip . map sanitizer+    where sanitizer c +              | c `elem` "\n\r\0\t" = ' '+              | otherwise = c++getContent (Document _ _ e _) = CElem e
+ INSTALL view
@@ -0,0 +1,10 @@+Sorry, need more here...++Try:++ghc --make -o setup Setup.lhs+./setup configure+./setup build+./setup install++To run, you will need to have curl installed
+ Setup.lhs view
@@ -0,0 +1,7 @@+#!/usr/bin/env runhugs+arch-tag: Main setup script++> import Distribution.Simple++> main = defaultMain+
+ Types.hs view
@@ -0,0 +1,46 @@+{- hpodder component+Copyright (C) 2006-2007 John Goerzen <jgoerzen@complete.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+-}++{- |+   Module     : Types+   Copyright  : Copyright (C) 2006-2007 John Goerzen+   License    : GNU GPL, version 2 or above++   Maintainer : John Goerzen <jgoerzen@complete.org>+   Stability  : provisional+   Portability: portable++Written by John Goerzen, jgoerzen\@complete.org++-}+module Types where+import Data.ConfigFile++data Command =+    Command {cmdname :: String,+             cmddescrip :: String,+             execcmd :: [String] -> Maybe FilePath -> ConfigParser -> IO ()}++data Message = Message {+      sId :: String,+      sSender :: String,+      sRecipient :: String,+      sText :: String,+      sDate :: String+    } deriving (Eq, Read, Show, Ord)+
+ Utils.hs view
@@ -0,0 +1,119 @@+{-+Copyright (C) 2006-2008 John Goerzen <jgoerzen@complete.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+-}++{- |+   Module     : Utils+   Copyright  : Copyright (C) 2006-2008 John Goerzen+   License    : GNU GPL, version 2 or above++   Maintainer : John Goerzen <jgoerzen@complete.org>+   Stability  : provisional+   Portability: portable++Written by John Goerzen, jgoerzen\@complete.org++-}++module Utils where+import System.Console.GetOpt+import Types+import System.Exit+import System.IO+import Data.ConfigFile+import Text.Regex.Posix+import Data.Either.Utils(forceEither)+import Network.URI+import Data.Maybe.Utils+import Text.Printf++simpleCmd :: String             -- ^ Command name+          -> String             -- ^ Command description+          -> String             -- ^ Command help text+          -> [OptDescr (String, String)] -- ^ Option descriptions+          -> (Maybe String -> ConfigParser -> ([(String, String)], [String]) -> IO ()) -- ^ Function to call +          -> (String, Command)+simpleCmd name descrip helptext optionsinp func =+    (name, Command {cmdname = name, cmddescrip = descrip,+                    execcmd = worker})+    where options =+              optionsinp ++ [Option "" ["help"] (NoArg ("help", "")) "Display this help"]+          worker argv cpath gi =+              case getOpt RequireOrder options argv of+                (o, n, []) -> +                    if (lookup "help" o == Just "") +                       then usageerror []+                       else func cpath gi (o, n)+                (_, _, errors) -> usageerror (concat errors)+          usageerror errormsg =+              do putStrLn $ "Error processing arguments for command " ++ +                          name ++ ":"+                 putStrLn errormsg+                 putStrLn (usageInfo header options)+                 putStrLn helptext+                 exitFailure+          header = "Available command-options for " ++ name ++ " are:\n"+                                                               +{-+lock func =+    do appdir <- getAppDir+       lockh <- openFile (appdir ++ "/.lock") WriteMode+       lockfd <- handleToFd lockh+       catch (placelock lockfd) errorhandler+       r <- finally func (releaselock lockfd)+       return r++    where placelock lockfd = setLock lockfd (WriteLock, AbsoluteSeek, 0, 0)+          releaselock lockfd = do+               setLock lockfd (Unlock, AbsoluteSeek, 0, 0)+               closeFd lockfd+          errorhandler _ =+              do putStrLn "Aborting because another twidge is already running"+                 exitFailure+-}++ex_tempfail = 75+ex_permfail = 69++permFail :: String -> IO a+permFail msg =+    do hPutStrLn stderr msg+       exitWith (ExitFailure ex_permfail)++serverHost cp = host+    where urlbase = forceEither $ get cp "DEFAULT" "urlbase"+          uri = forceMaybeMsg "genMsgId parseURI" $ parseURI urlbase+          host = uriRegName . forceMaybeMsg "genMsgId uriauth" . +                 uriAuthority $ uri++genMsgId :: String -> Message -> ConfigParser -> String+genMsgId section m cp =+    printf "<%s.%s.%s@%s.%s.twidge>" (sId m) (sSender m) (sRecipient m)+               section (serverHost cp) +-- FIXME: escape periods in serverHost++{- | Parses a message id, returning (Message, host, section).+The sText and sDate fiels will be empty. -}+parseMsgId :: String -> Maybe (Message, String, String)+parseMsgId msgid =+    case msgid =~ repat of+      [[_, id, sender, recipient, section, host]] -> +          Just (Message {sId = id, sSender = sender, sRecipient = recipient, +                         sText = "", sDate = ""},+                host, section)+      _ -> Nothing+    where repat = "^<([^.@]+)\\.([^.@]+)\\.([^@.]*)@([^.]+)\\.(.+)\\.twidge>"
+ doc/SConstruct view
@@ -0,0 +1,30 @@+# Copyright (C) 2004-2006 John Goerzen <jgoerzen@complete.org>+# <jgoerzen@complete.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++env = Environment()+env.Export("env")+env.Append(MASTERBASE = 'twidge', TOPNODE = 'twidge', DOINDEX = 1,+        PDFARGS = '-s local=printlocal')++execfile('sgml-common/SConstruct')++manpages = []+for manpage in ['twidge']:+    manpages.append(env.MAN('%s.1' % manpage, 'man.%s.sgml' % manpage))+env.Alias('manpages', manpages)++
+ doc/local.dsl view
@@ -0,0 +1,41 @@+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [+<!ENTITY dbstyle PUBLIC "-//GtkViaAlcove//DOCUMENT Gtk-doc HTML Stylesheet//EN" CDATA DSSSL>+]>++<style-sheet>+<style-specification use="gtk">+<style-specification-body>++(define (toc-depth nd)+  (if (string=? (gi nd) (normalize "book"))+      1+      1))+(define %generate-article-toc% #t)++;; Don't split up the doc as much.+(define (chunk-element-list)+  (list (normalize "preface")+        (normalize "chapter")+        (normalize "appendix")+        (normalize "article")+        (normalize "glossary")+        (normalize "bibliography")+        (normalize "index")+        (normalize "colophon")+        (normalize "setindex")+        (normalize "reference")+        (normalize "refentry")+        (normalize "part")+        (normalize "book") ;; just in case nothing else matches...+        (normalize "set")  ;; sets are definitely chunks...+        ))+++</style-specification-body>+</style-specification>+<external-specification id="gtk" document="dbstyle">+</style-sheet>++<!--+# arch-tag: web stylesheet for documentation+-->
+ doc/man.twidge.sgml view
@@ -0,0 +1,21 @@+<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [+<!ENTITY twidge "<application>twidge</application>">+<!ENTITY man.twidge SYSTEM "twidge-manpage.sgml">++    ]>++    <reference>+  <title>twidge Manual</title>+  +  &man.twidge;++    </reference>+++    <!--+    Local Variables:+    mode: sgml+    sgml-set-face: T+    End:++    -->
+ doc/printlocal.dsl view
@@ -0,0 +1,25 @@+<!DOCTYPE style-sheet PUBLIC "-//James Clark//DTD DSSSL Style Sheet//EN" [+<!ENTITY dbstyle PUBLIC "-//Norman Walsh//DOCUMENT DocBook Print Stylesheet//EN" CDATA DSSSL>+]>++<style-sheet>+<style-specification use="docbook">+<style-specification-body>++(define tex-backend #t)+(define bop-footnotes #t)+(define %two-side% #t)+(define %footnote-ulinks% #t)++;    (declare-characteristic heading-level+;          "UNREGISTERED::James Clark//Characteristic::heading-level" 4)+++</style-specification-body>+</style-specification>+<external-specification id="docbook" document="dbstyle">+</style-sheet>++<!--+# arch-tag: print stylesheet for manual+-->
+ doc/sgml-common/COPYING view
@@ -0,0 +1,342 @@+		    GNU GENERAL PUBLIC LICENSE+		       Version 2, June 1991++ Copyright (C) 1989, 1991 Free Software Foundation, Inc.+     59 Temple Place, Suite 330, Boston, MA  02111-1307  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 Library 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 Library General+Public License instead of this License.++# arch-tag: License for sgml-common
+ doc/sgml-common/COPYRIGHT view
@@ -0,0 +1,39 @@+Copyright for all code except ps2epsi+-------------------------------------+# Copyright (C) 2002, 2003 John Goerzen+# <jgoerzen@complete.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++Copyright for ps2epsi+---------------------+This program is free software; you can redistribute it and/or modify it+under the terms of the GNU General Public License as published by the+Free Software Foundation; either version 2, or (at your option) any+later version.++This program is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with this program; if not, write to the Free Software+Foundation, 59 Temple Place - Suite 330,+Boston, MA 02111-1307, USA.++My local changes were to the page size.++# arch-tag: Copyright statements and information for sgml-common
+ doc/sgml-common/ChangeLog view
@@ -0,0 +1,265 @@+# do not edit -- automatically generated by arch changelog+# arch-tag: automatic-ChangeLog--jgoerzen@complete.org--projects/sgml-common--head--1.0+#++2004-05-21 14:28:00 GMT	John Goerzen <jgoerzen@complete.org>	patch-20++    Summary:+      Fixed text target+    Revision:+      sgml-common--head--1.0--patch-20+++    modified files:+     ChangeLog SConstruct+++2004-02-27 15:22:59 GMT	John Goerzen <jgoerzen@complete.org>	patch-19++    Summary:+      Added manpage generation support+    Revision:+      sgml-common--head--1.0--patch-19+++    modified files:+     ChangeLog SConstruct+++2004-02-03 19:50:11 GMT	John Goerzen <jgoerzen@complete.org>	patch-18++    Summary:+      More clearing up of REs+    Revision:+      sgml-common--head--1.0--patch-18+++    modified files:+     ChangeLog SConstruct+++2004-02-03 19:40:22 GMT	John Goerzen <jgoerzen@complete.org>	patch-17++    Summary:+      Tightened up re for finding image tags+    Revision:+      sgml-common--head--1.0--patch-17+++    modified files:+     ChangeLog SConstruct+++2004-02-03 19:28:03 GMT	John Goerzen <jgoerzen@complete.org>	patch-16++    Summary:+      More changes to support scanner+    Revision:+      sgml-common--head--1.0--patch-16++    Removed outdated code and made more bugfixes relevant to documents without+    images or with only pre-generated images.++    new files:+     ChangeLog++    modified files:+     SConstruct+++2004-02-03 18:41:51 GMT	John Goerzen <jgoerzen@complete.org>	patch-15++    Summary:+      HTML gen now basically functional with scanning+    Revision:+      sgml-common--head--1.0--patch-15+++    modified files:+     SConstruct+++2004-02-03 17:41:51 GMT	John Goerzen <jgoerzen@complete.org>	patch-14++    Summary:+      Auto-scanning is now close for PDFs.+    Revision:+      sgml-common--head--1.0--patch-14+++    modified files:+     SConstruct+++2004-02-03 16:59:02 GMT	John Goerzen <jgoerzen@complete.org>	patch-13++    Summary:+      Scanners starting to work+    Revision:+      sgml-common--head--1.0--patch-13+++    modified files:+     SConstruct+++2004-02-03 16:22:51 GMT	John Goerzen <jgoerzen@complete.org>	patch-12++    Summary:+      Cleaned up HTML situation+    Revision:+      sgml-common--head--1.0--patch-12+++    modified files:+     SConstruct+++2004-02-02 22:33:50 GMT	John Goerzen <jgoerzen@complete.org>	patch-11++    Summary:+      SConstruct file now working+    Revision:+      sgml-common--head--1.0--patch-11+++    modified files:+     SConstruct+++2004-02-02 22:07:27 GMT	John Goerzen <jgoerzen@complete.org>	patch-10++    Summary:+      Fixed nasty PNG gen bug+    Revision:+      sgml-common--head--1.0--patch-10+++    modified files:+     SConstruct+++2004-02-02 21:57:32 GMT	John Goerzen <jgoerzen@complete.org>	patch-9++    Summary:+      Checkpointing some more...+    Revision:+      sgml-common--head--1.0--patch-9+++    modified files:+     SConstruct+++2004-02-02 21:37:29 GMT	John Goerzen <jgoerzen@complete.org>	patch-8++    Summary:+      Checkpointing some more...+    Revision:+      sgml-common--head--1.0--patch-8+++    modified files:+     SConstruct+++2004-02-02 20:19:02 GMT	John Goerzen <jgoerzen@complete.org>	patch-7++    Summary:+      Checkpointing+    Revision:+      sgml-common--head--1.0--patch-7+++    modified files:+     SConstruct+++2004-02-02 19:18:40 GMT	John Goerzen <jgoerzen@complete.org>	patch-6++    Summary:+      Added Plucker+    Revision:+      sgml-common--head--1.0--patch-6+++    modified files:+     SConstruct+++2004-02-02 19:09:16 GMT	John Goerzen <jgoerzen@complete.org>	patch-5++    Summary:+      Added cleanup rules+    Revision:+      sgml-common--head--1.0--patch-5+++    modified files:+     SConstruct+++2004-02-02 18:58:11 GMT	John Goerzen <jgoerzen@complete.org>	patch-4++    Summary:+      sources now checks only chapters/ to prevent dep cycle with index+    Revision:+      sgml-common--head--1.0--patch-4+++    modified files:+     Makefile.common SConstruct {arch}/=tagging-method+++2004-02-02 17:51:27 GMT	John Goerzen <jgoerzen@complete.org>	patch-3++    Summary:+      Experimental SCons conversion+    Revision:+      sgml-common--head--1.0--patch-3+++    new files:+     SConstruct+++2003-10-21 20:24:04 GMT	John Goerzen <jgoerzen@complete.org>	patch-2++    Summary:+      Added plain text generation target+    Revision:+      sgml-common--head--1.0--patch-2++    Added plain text generation target+    ++    modified files:+     ./Makefile.common+++2003-09-10 14:27:58 GMT	John Goerzen <jgoerzen@complete.org>	patch-1++    Summary:+      Minor updates to PNG generation and gtk-doc icon locations+    Revision:+      sgml-common--head--1.0--patch-1+++    modified files:+     Makefile.common+++2003-09-10 14:24:24 GMT	John Goerzen <jgoerzen@complete.org>	base-0++    Summary:+      initial import+    Revision:+      sgml-common--head--1.0--base-0++    +    (automatically generated log message)++    new files:+     COPYING COPYRIGHT Makefile.common ps2epsi++
+ doc/sgml-common/Makefile.common view
@@ -0,0 +1,229 @@+# -*- Mode: makefile; -*-+# arch-tag: Primary sgml-common top-level Makefile+# Common Makefile for SGML documents+#+# Copyright (C) 2002, 2003 John Goerzen+# <jgoerzen@complete.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++# The following variables should be set:+# MASTERBASE -- basename of master file -- example: my-guide+# BASICDEPS -- various dependencies of the master file.  For instance,+#   this might include files included in the SGML.  It could also be empty.+# TOPNODE -- Basename of top id for HTML link.++MASTER := $(MASTERBASE).sgml+FIGUREDIRS := $(wildcard figures/*)+DOINDEX ?= yes++######################################################################+# Index generation+######################################################################++ifeq ($(DOINDEX), yes)++INDEXSGMLFILE := index/index.sgml+INDEXDATAFILE := index/HTML.index++$(INDEXSGMLFILE): $(INDEXDATAFILE)+	@echo " *** Generating SGML index from index list"+	collateindex.pl -i ch.index -g -o index/index.sgml index/HTML.index++$(INDEXDATAFILE): $(MASTER) $(BASICDEPS)+#	jade -t sgml -d docbook.dsl -V html-index $(MASTER)+#	jade -t sgml -V html-index $(MASTER)+	@echo " *** Generating index list from document"+	-rm -r index+	mkdir index+	collateindex.pl -i ch.index -N -o index/index.sgml+	#mkdir html-temp+	#docbook2html --output html-temp -V html-index $(MASTER)+	docbook-2-html -O -V -O html-index $(HTMLARGS) $(MASTER)+	mv $(MASTERBASE)-html/HTML.index index/+	rm -r $(MASTERBASE)-html+endif # DOINDEX++######################################################################+# Text generation+######################################################################+$(MASTERBASE).txt: $(MASTER) $(BASICDEPS) $(INDEXSGMLFILE)+	@echo " *** Generating text output"+	docbook2txt $(MASTER)++######################################################################+# PostScript generation+######################################################################++$(MASTERBASE).ps: $(MASTER) $(BASICDEPS) $(INDEXSGMLFILE) $(EPSFILES)+	@echo " *** Generating PostScript output"+# This works too: docbook2ps -V paper-size=Letter $(MASTER)+	docbook-2-ps -q -O -V -O paper-size=Letter $(PSARGS) $(MASTER)++######################################################################+# Figure generation+######################################################################++%_1.epi: %.ps+	$(get-epi)+%_2.epi: %.ps+	$(get-epi)+%_3.epi: %.ps+	$(get-epi)+%_4.epi: %.ps+	$(get-epi)+%_5.epi: %.ps+	$(get-epi)+%_6.epi: %.ps+	$(get-epi)+%_7.epi: %.ps+	$(get-epi)+%_8.epi: %.ps+	$(get-epi)+%_9.epi: %.ps+	$(get-epi)+%_10.epi: %.ps+	$(get-epi)+%_11.epi: %.ps+	$(get-epi)+%_12.epi: %.ps+	$(get-epi)++%_1_l.epi: %.ps+	$(get-epil)+%_2_l.epi: %.ps+	$(get-epil)+%_3_l.epi: %.ps+	$(get-epil)+%_4_l.epi: %.ps+	$(get-epil)+%_5_l.epi: %.ps+	$(get-epil)+%_6_l.epi: %.ps+	$(get-epil)+%_7_l.epi: %.ps+	$(get-epil)+%_8_l.epi: %.ps+	$(get-epil)+%_9_l.epi: %.ps+	$(get-epil)+%_10_l.epi: %.ps+	$(get-epil)+%_11_l.epi: %.ps+	$(get-epil)+%_12_l.epi: %.ps+	$(get-epil)++%.png: %_l.epi+	@echo " *** Generating PNG image for $<"+	gs -q -dTextAlphaBits=4 -dGraphicsAlphaBits=4 -r90 -dBATCH -dNOPAUSE \+		-dSAFER -sOutputFile=$@ -sDEVICE=png16m $< -c showpage++%.ps: %.pdf+	pdftops $<++######################################################################+# HTML generation+######################################################################++define copy-figures-worker+mkdir html/figures+for DIRECTORY in $(FIGUREDIRS); do mkdir html/$$DIRECTORY; cp -v $$DIRECTORY/*.png html/$$DIRECTORY/; done+endef++define copy-figures+$(if $(FIGUREDIRS),$(copy-figures-worker))+endef++html/index.html: $(MASTER) $(BASICDEPS) $(INDEXSGMLFILE) $(PNGFILES)+	@echo " *** Generating HTML output"+	-rm -r html+	mkdir html+	#docbook2html --output html $(MASTER)+	docbook-2-html $(HTMLARGS) $(MASTER)+	mv $(MASTERBASE)-html/* html/+	rmdir $(MASTERBASE)-html+	$(copy-figures)+#	tidy -m html/*.html+	ln -s $(TOPNODE).html html/index.html+	-cp -v /usr/share/gtk-doc/data/*.png html/++######################################################################+# Cleaning+######################################################################++clean:+	-rm -f `find . -name "*~"` `find . -name "*.png"` `find . -name "*.epi"`+	-rm -r html-temp html index $(MASTERBASE).txt+	-rm *.aux *.log *.dvi *.tex *.jtex *.ps *.html *.log *.out jadetex.cfg+	-rm *.ps html/*.html figures/topology/*.epi figures/topology/*.png+	-rm *.log *.pdb+	-rm `find . -name ".ps"` `find . -name "*.epi"` *.pdf+	-rm `find . -name "*.png"`++######################################################################+# Utility functions+######################################################################++GETPAGE=$(shell echo $(1) | sed -e "s/^.*_\([0-9]*\).epi/\\1/g")+define get-epi+@echo " *** Generating EPI image for $<"+psselect -q $(call GETPAGE,$@) $< temp.ps+psresize -w 6.375in -h 8.25in temp.ps temp2.ps+../sgml-common/ps2epsi temp2.ps $@+rm temp.ps temp2.ps+endef++GETPAGEL=$(shell echo $(1) | sed -e "s/^.*_\([0-9]*\)_l.epi/\\1/g")+define get-epil+@echo " *** Generating large EPI image for $<"+psselect -q $(call GETPAGEL,$@) $< temp.ps+psresize -w 8.5in -h 11in temp.ps temp2.ps+../sgml-common/ps2epsi temp2.ps $@+rm temp.ps temp2.ps+endef+++pdf: $(MASTERBASE).pdf++$(MASTERBASE).pdf: $(MASTERBASE).ps+	ps2pdf14 $(MASTERBASE).ps++plucker: $(MASTERBASE).pdb+$(MASTERBASE).pdb: html+	plucker-build --bpp=4 --compression=zlib --doc-name="$(MASTERBASE)" \+	-H file:`pwd`/html/index.html -M 5 \+	--maxheight=320 --maxwidth=310 \+	--staybelow=file:`pwd`/html --title="$(MASTERBASE)" -p . \+	-f $(MASTERBASE)++###########################################################################+# These are obsolete but should still work.+###########################################################################+++$(MASTERBASE).dvi: $(MASTERBASE).tex+	@echo " *** Generating DVI file."+	jadetex unix-guide.tex+	jadetex unix-guide.tex+	jadetex unix-guide.tex++$(MASTERBASE).tex: $(MASTER) $(BASICDEPS) $(INDEXSGMLFILE)+	@echo " *** Generating TeX files."+	docbook2tex -V paper-size=Letter $(MASTER)+#	jade -t tex -V tex-backend -d \+#		/usr/share/sgml/docbook/stylesheet/dsssl/modular/print/docbook.dsl \+#		$(MASTER)+
+ doc/sgml-common/SConstruct view
@@ -0,0 +1,208 @@+# vim: set filetype=python :+# arch-tag: general-purpose SCons build file for sgml-common++from glob import glob+import os, re++############################################################+# Setup+############################################################++SConsignFile('.sconsign-master')+#Import('env')+d = env.Dictionary()+if not 'JADE' in d:+    d['JADE'] = 'jade'+if not 'INDEXNODE' in d:+    d['INDEXNODE'] = 'ch.index'+if not 'GTKIMGPATH' in d:+    d['GTKIMGPATH'] = '/usr/share/gtk-doc/data'+if not 'PS2EPSI' in d:+    d['PS2EPSI'] = '../sgml-common/ps2epsi'++def removeindex(l):+    while 'index/index.sgml' in l:+        l.remove('index/index.sgml')++master = d['MASTERBASE'] +mastersgml = master + '.sgml'+sources = [mastersgml] + glob('*/*.sgml') + glob('*/*/*.sgml')+removeindex(sources)+db2htmlcmd = 'docbook-2-html -D $JADE ${HTMLARGS}  ${SOURCE}'+db2htmlindexcmd = 'docbook-2-html -D $JADE -O -V -O html-index ${HTMLARGS} ${SOURCE}'++##################################################+# SCANNERS+##################################################+def recursescan(scanner, node, env):+    result = scanner(node, env) +    retval = []+    for item in result:+        retval.append(item)+        retval.extend(recursescan(scanner, item, env))+    return retval++SGML_includes_re = re.compile(r'<!ENTITY[^>]+SYSTEM[^>]+"(.+)"', re.M)+def SGML_includes_scan(node, env, path):+    ret = SGML_includes_re.findall(node.get_contents())+    removeindex(ret)+    return ret++SGML_includes_scanner = Scanner(name = 'SGML_includes',+    function = SGML_includes_scan, recursive = 1, skeys = ['.sgml', '.ent'])++SGML_image_pdf_re = re.compile(r'<(graphic|imagedata).+?fileref="([^"]+\.pdf)"', re.S)+SGML_image_png_re = re.compile(r'<(graphic|imagedata).+?fileref="([^"]+\.png)"', re.S)+def SGML_image_scanner(node, env, path, arg):+    root, ext = os.path.splitext(str(node))+    contents = node.get_contents()+    return SGML_includes_scan(node, env, path) + \+            [os.getcwd() + '/' + x[1] for x in arg.findall(contents)]++SGML_pdf_scanner = Scanner(name = 'SGML_pdf',+         function = SGML_image_scanner, argument = SGML_image_pdf_re,+         recursive = 1)+SGML_png_scanner = Scanner(name = 'SGML_png',+        function = SGML_image_scanner, argument = SGML_image_png_re,+        recursive = 1)++##################################################+# BUILDERS+##################################################++#### PLAIN TEXT+Btxt = Builder(action="docbook2txt $SOURCE", src_suffix='.sgml', suffix='.txt')++#### PDF / POSTSCRIPT+Bpdf = Builder(action="docbook-2-pdf -D ${JADE} -q -O -V -O paper-size=Letter ${PDFARGS} ${SOURCE}",+        src_suffix='.sgml', suffix='.pdf')+Bpdf2ps = Builder(action="pdftops ${SOURCE}", src_suffix='.pdf', suffix='.ps')++#### MAN PAGES+# FIXME: test this+Bman = Builder(action="docbook2man $SOURCE", src_suffix='.sgml', suffix='.1')++#### HTML+Bhtml = Builder(action = [ \+        'if test -d ${TARGET.dir} ; then rm -r ${TARGET.dir} ; fi',+        'mkdir ${TARGET.dir}',+        db2htmlcmd,+        'mv ${MASTERBASE}-html/* ${TARGET.dir}/',+        'rmdir ${MASTERBASE}-html',+        'ln -s ${TOPNODE}.html ${TARGET.dir}/index.html',+        'cp ${GTKIMGPATH}/*.png ${TARGET.dir}/'])++#### PNG+Bepip2png = Builder(action = 'gs -q -dTextAlphaBits=4 -dGraphicsAlphaBits=4 ' +\+        '-r90 -dBATCH -dNOPAUSE -dSAFER -sOutputFile=$TARGET ' + \+        '-sDEVICE=png16m $SOURCE -c showpage', suffix='.png', src_suffix='.pngepi')++#### EPI from PS+def getpagenumfromname(target, source, env, for_signature):+    return re.search('^.*_(\d+)\.(png){0,1}epi$', str(target[0])).group(1)+d['GETPAGE'] = getpagenumfromname++Aps2epi = Action(['psselect -q ${GETPAGE} $SOURCE temp.ps',+        'psresize -w ${WIDTH} -h ${HEIGHT} temp.ps temp2.ps',+        '$PS2EPSI temp2.ps $TARGET',+        'rm temp.ps temp2.ps'])+Bps2epi = Builder(action=Aps2epi, src_suffix='.ps', suffix='.epi')+Bps2epip = Builder(action=Aps2epi, src_suffix='.ps', suffix='.pngepi')+Bepi2pdf = Builder(action="epstopdf -o=${TARGET} ${SOURCE}", suffix='.pdf',+        src_suffix='.epi')++#### PLUCKER+Bplucker = Builder(action = 'plucker-build --bpp=4 --compression=zlib ' + \+        '--doc-name="${MASTERBASE}" -H file:${SOURCE.abspath} -M 5 ' + \+        '--maxheight=320 --maxwidth=310 --staybelow=file:`pwd`/${SOURCE.dir} ' + \+        '--title="${MASTERBASE}" -p . -f ${MASTERBASE}')++##################################################+# General setup+##################################################++env.Append(BUILDERS = {'Text': Btxt, 'PDF2PS': Bpdf2ps, 'PDF': Bpdf, 'HTML': Bhtml,+        'Plucker': Bplucker, 'PS2EPI': Bps2epi, 'PS2EPIP': Bps2epip,+        'EPI2PDF': Bepi2pdf, 'EPIP2PNG': Bepip2png, 'MAN': Bman})++#### INDEX GENERATION+if 'DOINDEX' in d:+    Bindex = Builder(action = ['if test -d ${TARGET.dir}  ; then rm -r ${TARGET.dir} ; fi',+        "mkdir ${TARGET.dir}",+        "collateindex.pl -i $INDEXNODE -N -o $TARGET",+        db2htmlindexcmd,+        "mv ${MASTERBASE}-html/HTML.index ${TARGET.dir}/",+        "rm -r ${MASTERBASE}-html",+        "collateindex.pl -i $INDEXNODE -g -o $TARGET ${TARGET.dir}/HTML.index"])+    env['BUILDERS']['Index'] = Bindex+    index = env.Index('index/index.sgml', mastersgml)+    env.Depends(index, sources)+    env.Clean(index, 'index')+    deps = sources + [index]+else:+    deps = sources++##################################################+# BUILD RULES+###################################################+# Text+text = env.Text(mastersgml)+env.Depends(text, deps)+env.Alias('text', text)++# PDF+pdfsgml = File(mastersgml)+pdf = env.PDF(pdfsgml)+figsindoc = [x for x in recursescan(SGML_pdf_scanner, pdfsgml, env) if str(x).endswith('.pdf')]+epipdf = []+for file in figsindoc:+    pdfname = re.sub('_\d+\.pdf$', '.pdf', str(file))+    if pdfname == str(file):+        # This is not a filename that fits our pattern; add unmodified.+        epipdf.append(file)+        continue+    psfile = env.PDF2PS(source = pdfname)+    epifile = env.PS2EPI(str(file).replace(".pdf", ".epi"), psfile,+            WIDTH='6.375in', HEIGHT='8.25in')+    epipdf.append(env.EPI2PDF(source = epifile))++env.Depends(pdf, deps)+env.Depends(pdf, epipdf)+env.Alias('pdf', pdf)+env.Clean(pdf, ['jadetex.cfg', '${MASTERBASE}.aux', '${MASTERBASE}.dvi',+        '${MASTERBASE}.jtex', '${MASTERBASE}.log', '${MASTERBASE}.out',+        'jade-out.fot'])++# PS+ps = env.PDF2PS(source = pdf)+env.Alias('ps', ps)++# HTML+htmlsgml = File(mastersgml)+buildhtml = env.HTML('html/index.html', htmlsgml)+figsindoc = [x for x in recursescan(SGML_png_scanner, htmlsgml, env) if str(x).endswith('.png')]+epipng = []+for file in figsindoc:+    pdfname = re.sub('_\d+\.png$', '.pdf', str(file))+    if pdfname == str(file):+        # This is not a filename that fits our pattern; add unmodified. +        epipng.append(file)+        continue+    psfile = env.PDF2PS(source = pdfname)+    epifile = env.PS2EPIP(str(file).replace(".png", ".pngepi"), psfile,+            WIDTH='8.5in', HEIGHT='11in')+    epipng.append(env.EPIP2PNG(source = epifile))++env.Depends(buildhtml, epipng)+env.Depends(buildhtml, deps)+pnginstalls = env.InstallAs(['html/' + str(x) for x in epipng], epipng)+env.Depends(pnginstalls, buildhtml)+html = env.Alias('html', buildhtml)+html = env.Alias('html', pnginstalls)+env.Clean(buildhtml, 'html')++# Plucker+plucker = env.Plucker(master + '.pdb', 'html/index.html')+env.Alias('plucker', plucker)++env.Default(html)
+ doc/sgml-common/ps2epsi view
@@ -0,0 +1,77 @@+#!/bin/sh+# $RCSfile: ps2epsi,v $ $Revision: 1.4.2.2 $+# arch-tag: ps2epsi customized for sgml-common++tmpfile=/tmp/ps2epsi$$++export outfile++if [ $# -lt 1 -o $# -gt 2 ]; then+	echo "Usage: `basename $0` file.ps [file.epsi]" 1>&2+	exit 1+fi++infile=$1;++if [ $# -eq 1 ]+then+	case "${infile}" in+	  *.ps)		base=`basename ${infile} .ps` ;;+	  *.cps)	base=`basename ${infile} .cps` ;;+	  *.eps)	base=`basename ${infile} .eps` ;;+	  *.epsf)	base=`basename ${infile} .epsf` ;;+	  *)		base=`basename ${infile}` ;;+	esac+	outfile=${base}.epsi+else+	outfile=$2+fi++ls -l ${infile} |+awk 'F==1	{+		cd="%%CreationDate: " $6 " " $7 " " $8;+		t="%%Title: " $9;+		f="%%For:" U " " $3;+		c="%%Creator: Ghostscript ps2epsi from " $9;+		next;+		}+	/^%!/	{next;}+	/^%%Title:/	{t=$0; next;}+	/^%%Creator:/	{c=$0; next;}+	/^%%CreationDate:/	{cd=$0; next;}+	/^%%For:/	{f=$0; next;}+	!/^%/	{+		print "/ps2edict 30 dict def";+		print "ps2edict begin";+		print "/epsititle (" t "\\n) def";+		print "/epsicreator (" c "\\n) def";+		print "/epsicrdt (" cd "\\n) def";+		print "/epsifor (" f "\\n) def";+		print "end";+		exit(0);+		}+	' U="$USERNAME$LOGNAME"  F=1 - F=2 ${infile} >$tmpfile++gs -q -dNOPAUSE -dSAFER -dDELAYSAFER -r72 -sDEVICE=bit -sOutputFile=/dev/null $tmpfile ps2epsi.ps $tmpfile <${infile} 1>&2+rm -f $tmpfile++(+cat << BEGINEPS+save countdictstack mark newpath /showpage {} def /setpagedevice {pop} def+%%EndProlog+%%Page 1 1+BEGINEPS++cat ${infile} |+sed -e '/^%%BeginPreview:/,/^%%EndPreview[^!-~]*$/d' -e '/^%!PS-Adobe/d'\+    -e '/^%%[A-Za-z][A-Za-z]*[^!-~]*$/d' -e '/^%%[A-Za-z][A-Za-z]*: /d'++cat << ENDEPS+%%Trailer+cleartomark countdictstack exch sub { end } repeat restore+%%EOF+ENDEPS++) >> ${outfile}++exit 0
+ doc/twidge-manpage.sgml view
@@ -0,0 +1,872 @@+  <refentry id="twidge">+  <indexterm><primary>twidge</><secondary>Reference For</></>+  <refentryinfo>+    <address><email>jgoerzen@complete.org</email></address>+    <author><firstname>John</firstname><surname>Goerzen</surname></author>+  </refentryinfo>++  <refmeta>+    <refentrytitle>twidge</refentrytitle>+    <manvolnum>1</manvolnum>+    <refmiscinfo>John Goerzen</refmiscinfo>+  </refmeta>++  <refnamediv>+    <refname>twidge</refname>+    <refpurpose>Microblogging client for Twitter, Identica</refpurpose>+  </refnamediv>++  <refsynopsisdiv>+    <cmdsynopsis>+      <command>twidge</command>+      <arg choice="opt">-d</arg>+      <arg choice="opt">-c <replaceable>FILE</replaceable></arg>+      <arg choice="plain"><replaceable>command</replaceable></arg>+      <arg choice="opt"><replaceable>command_args</replaceable></arg>+    </cmdsynopsis>+    <cmdsynopsis>+      <command>twidge</command>+      <arg choice="plain">--help</arg>+    </cmdsynopsis>+  </refsynopsisdiv>++  <refsect1 id="twidge.description">+    <title>Description</title>+    <para>+      &twidge; is a client for microblogging sites such as +      <ulink url="http://twitter.com/">Twitter</ulink> and+      <ulink url="http://identi.ca/">Identica</ulink> (identi.ca).+      Microblogging sites let you post short one-paragraph updates,+      follow the updates that your friends post, and interact with+      everyone in the site in a conversation style.+    </para>+    <para>+      &twidge; is a client to make working with microblogging sites+      faster and easier.  It is extremely versatile, and can be+      customized to work the way you want to work, and combined with+      other tools to do just about anything.+    </para>+    <para>+      &twidge; can be used quite nicely interactively from the shell.+      It is useful directly as-is, and with simple shell aliases can+      make a highly efficient system to do exactly what you want.  It+      is perfectly capable of being your only client for+      microblogging.+    </para>+    <para>+      &twidge; also can be used in an automated way, via+      <command>cron(1)</command>, or it can even integrate with your+      email system.+    </para>+    <para>+      A full list of &twidge; features, along with numerous+      suggestions on how to use it, can be found at the &twidge;+      website at <ulink+      url="http://software.complete.org/twidge"></ulink>.+    </para>+    +    <para>+      But, if you'd like to get going RIGHT NOW, skip to the Quick+      Start section below.  For now, I'll summarize a few &twidge;+      features; a more comprehensive list is on the website.+    </para>++    <refsect2 id="twidge.features">+      <title>Feature List</title>+      <itemizedlist>+        <listitem><para>Convenient, easy to learn, and fast command-line+            interface (it's simple to do simple things, and+            advanced things are possible)</para>+        </listitem>++        <listitem><para>This extensive manual, and numerous examples+        on the website</para></listitem>++        <listitem><para>Compatible with any microblogging service that+            implements the Twitter API.  Tested with Twitter and+            Identica (identi.ca).  Should be compatible with any other+            system.+          </para></listitem>++        <listitem><para>Full support for reading the activity of your+            friends, replies to you, and your own+            activity.</para></listitem>++        <listitem><para>Optional capability to remember what you have+            seen already and suppress those updates in future+            runs.</para></listitem>++        <listitem><para>Optional automatic shortening of long URLs via tinyurl.com</para></listitem>+        +        <listitem><para>Optional integration with your email system --+            send and receive updates via email.</para></listitem>++        <listitem><para>Specifically designed to be friendly to use in+            shell scripts.</para></listitem>++        <listitem><para>Shell scripting makes it easy to do many+            things, such as scheduling future updates (with+            <command>at</command>), ignoring certain updates+            (with <command>grep</command>), etc.</para></listitem>+        +        <listitem><para>Easy use of multiple accounts by having+            multiple configuration profiles.   Mechanism lends itself+            to shell aliases and tools.</para></listitem>++        <listitem><para>Small, minimalist footprint</para>+        </listitem>++        <listitem><para>Output formats are easily parsed.  Input+            formats are easily generated.  Configuration file format is+            liberal and easy to generate.+          </para></listitem>++        <listitem><para>Robust error detection and recovery+        throughout.+          </para></listitem>+      </itemizedlist>+    </refsect2>++  </refsect1>++  <refsect1 id="twidge.quickstart">+    <title>Quick Start</title>+    <para>+      This section will describe how a first-time &twidge; user can+      get up and running quickly.  It assumes you already have+      &twidge; compiled or installed on your system.  If not,+      please follow the instructions in the+      <filename>INSTALL</filename>+      file in the+      source distribution.+    </para>+    <para>+      To get started, simply run <command>twidge setup</command> at your+      shell prompt.  &twidge; will lead you through the first-time+      configuration -- which is only two questions and completely+      self-explanatory!+    </para>+    <para>+      Now, let's start exploring.  <command>twidge lsrecent+      -su</command> will show you the 20 most recent updates from the+      people you follow.  After the first time, it will remember what+      you've seen and only show you new updates.  In place of+      <command>lsrecent</command>, you could substitue+      <command>lsreplies</command> to replies to you.  You can also+      run <command>twidge lsrecent --help</command>, or refer to this+      document, for more details on the command.  In short, -s tells+      the system to save what you've seen, and -u tells it to only+      show you unseen items.+    </para>+    <para>+      You can subscribe to updates from friends by running+      <command>twidge follow+      <replaceable>nick</replaceable></command>.  To subscribe to+      updates for &twidge; itself, you'd run <command>twidge follow+      unixtwidge</command>.  If you've had enough of updates from+      someone, just use the <command>twidge unfollow</command> command.+    </para>+    <para>+      Now, how about posting your own updates?  Just type+      <command>twidge update</command>.  Type your update, and press+      Enter when done.  Your update may scroll past the end of the+      screen; don't worry about it.  Just don't hit Enter until you're+      done.  You can also pass your update on the command line, taking+      care to quote it if it contains spaces or shell characters.+    </para>+    <para>+      That's the quick tour.  For many more examples, refer to the+      website.+    </para>+  </refsect1>++  <refsect1 id="twidge.options">+    <indexterm><primary>Options (command-line)</primary></indexterm>+    <title>Options</title>+    <para>+      &twidge; always is invoked with the name of a specific+      operation, such as <option>update</option> or+      <option>lsrecent</option>.  In &twidge;, these operations are+      called <emphasis>commands</emphasis>.  Each command has its+      own options, which are given after the command on the+      &twidge; command line.  A full summary of each command's+      options is given later in this manual.+    </para>+    +    <para>+      You may obtain a list of all commands with <command>twidge+        lscommands</command>.  Help is available for any individual+      command with <command>twidge <replaceable>command</replaceable>+        --help</command>.  Global help is available with+      <command>twidge --help</command>.+    </para>+    <refsect2 id="twidge.options.global">+      <title>Global Options</title>+      <para>+        These options may be specified <emphasis>before</emphasis> any+        command.+      </para>+      <variablelist>+        <varlistentry><term>-c <replaceable>FILE</replaceable></term>+                      <term>--config=<replaceable>FILE</replaceable></term>+          <listitem><para>+              By default, &twidge; uses+              <filename>~/.twidgerc</filename> for configuration.+              With this option, you can specify an alternate file.+              &twidge; will read configuration information+              from it.  In certain cases, &twidge; will also write to+              it, such as with the <command>twidge setup</command>+              command, or the -s option to one of the ls commands.+            </para>+          </listitem>+        </varlistentry>+        <varlistentry><term>-d</term><term>--debug</term>+          <listitem><para>+              Enables debugging output.  This verbose output helps you+              learn what &twidge; is doing every step of the way and+              diagnose any problems you may encounter.+            </para>+          </listitem>+        </varlistentry>+      </variablelist>+    </refsect2>++  </refsect1>++  <refsect1 id="twidge.commands">+    <indexterm><primary>Commands</primary></indexterm>+    <title>Commands in Twidge</title>+    <para>+      &twidge; has many different commands.  You must specify a+      command when using &twidge;.+      This section will discuss each command in+      detail.  Note that all commands are case-sensitive and should be+      <emphasis>given in lowercase</emphasis>.+    </para>+    <para>+      All commands support the option <option>--help</option>.  Running+      <command>twidge <replaceable>command</replaceable>+      --help</command> will display information about the command and+      its options.  Since all commands support this, it won't be+      explicitly listed for each command below.+    </para>++  </refsect1>+  <refsect1 id="twidge.commands.updatedisplay">+    <title>Commands to Display Updates</title>+    <cmdsynopsis>+        <command>twidge ls<replaceable>*</replaceable></command>+        <arg choice="opt">-a</arg>+        <arg choice="opt">-l</arg>+        <arg choice="opt">-s</arg>+        <arg choice="opt">-u</arg>+    </cmdsynopsis>+    <para>+      Several commands can display updates from yourself or others.+      They all share a common syntax and common set of options.  The+      commands are <command>lsarchive</command>,+      <command>lsdm</command>, <command>lsdmarchive</command>,+      <command>lsrecent</command>, and <command>lsreplies</command>.+      Here are the common options:+    </para>+    +    <variablelist>+      <varlistentry><term>-a</term>+        <term>--all</term>+        <listitem><para>+            Normally, microblogging sites return one "page" of results+            -- typically, 20 or 100 results, depending on the+            operation.  Specifying --all requests &twidge; to+            continually send requests to the microblogging site until+            it receives an entire set of information.  Normally this+            is a bad idea, but when used in combination with -u --+            especially if you have used -s before -- it can be a+            useful way to poll for all new updates.+          </para>+          <para>+            If not used carefully, this command can generate many+            requests to the server and can use a significant amount of+            bandwidth.  Microblogging sites have traffic limits, and+            will not take kindly to this.  Be careful when you use+            --all.+          </para>+        </listitem>+      </varlistentry>++      <varlistentry><term>-e <replaceable>command</replaceable></term>+        <term>--exec=<replaceable>command</replaceable></term>+        <listitem><para>+            Causes any normal output to be suppressed.  Instead, for+            each item that is retrieved, call the given command.  The+            command will be passed exactly four arguments.  Care+            should be exercised when using them in shell scripts due+            to the likelihood of the presence of shell+            metacharacters.  The arguments are:+          </para>+          <orderedlist>+            <listitem><para>+                The update ID for the given update.+              </para></listitem>+            <listitem><para>+                The username that created the update</para></listitem>+            <listitem><para>+                A suggested Message-ID for representing the update in+                email.  Contains the enclosing angle brackets.+              </para></listitem>+            <listitem><para>+                The update text itself.  Likely contains spaces and+                other shell metacharacters.+              </para></listitem>+          </orderedlist>+        </listitem>+      </varlistentry>++      <varlistentry><term>-l</term>+        <term>--long</term>+        <listitem><para>+            The default output format shows a nickname and a message,+            formatted nicely for display.  Using this option causes+            output to include these columns: message ID, sender nick,+            recipient nick (empty unless a direct message), update+            text, and date created.+            The output format is suitable for machine parsing. +            horizontal tab character \t separates the columns,+            and is guaranteed to appear nowhere else.  It is also+            guaranteed that \n will appear nowhere within a line when+            using -l.+          </para>+          <para>+            The columns as presented are anticipated to remain+            stable.  However, additional columns could be added to the+            right of these columns in future versions of &twidge;.+            Well-behaved parsers should be prepared to discard any+            surplus columns to the right of those specified in this+            document.+          </para>+        </listitem>+        </varlistentry>++      <varlistentry>+        <term>-m <replaceable>address</replaceable></term>+        <term>--mailto=<replaceable>address</replaceable></term>+        <listitem><para>+            Causes any normal output to be suppressed.  Instead, for+            each item that is retrieved, generate an email and send it+            to the given address.  The subject line will contain the+            sender nickname and the first 30 characters of the text.+            The body will contain+            the entire text.  The message is sent by using the program+            listed as sendmail in the configuration file.  If mailfrom+            is listed in the configuration file, it is listed as the+            from address and the name of the sender is listed as the+            from comment.+          </para>+          <para>+            A Message-ID designed to uniquely identify this update is+            generated and included.  In addition, headers beginning+            with X-Twidge- will be added, with various metadata.+          </para>+          <para>+            It should be noted that a simple script could be used with+            --exec to achieve this same purpose, but with greater+            flexibility.+            The functionality is built into &twidge; as well for+            convenience.+          </para>+        </listitem>+      </varlistentry>++      <varlistentry><term>-s</term>+        <term>--saveid</term>+        <listitem><para>+            Saves the ID of the most recent fetched message for future+            use with -u.  Requires write access to your configuration+            file.+          </para></listitem>+      </varlistentry>++      <varlistentry><term>-u</term>+        <term>--unseen</term>+        <listitem><para>+            Causes the command to show only items since the last use+            of -s with this particular command.  If -s has never+            before been used with this command, has no effect.+          </para>+          <para>+            As of September 2008, Identi.ca does not support the+            since_id parameter that is required for this option to be+            effective.  A future version of &twidge; may implement a+            workaround.+          </para>+        </listitem>+      </varlistentry>+    </variablelist>++    <para>+      Some of these options don't make sense together; for instance,+      --long, --exec, and --mailto are mutually exclusive.  Results+      are undefined if you use such options simultaneously.+    </para>++    <refsect2 id="twidge.commands.lsarchive">+      <title>lsarchive</title>+      <para>+        Lists your own posts.+      </para>+    </refsect2>++    <refsect2 id="twidge.commands.lsdm">+      <title>lsdm</title>+      <para>+        Lists direct messages sent to you.  Note: identi.ca does not+        support direct messages, and this will cause an error with+        that service.+      </para>+    </refsect2>++    <refsect2 id="twidge.commands.lsdmarchive">+      <title>lsdmarchive</title>+      <para>+        Lists direct messages you have sent.  Note: identi.ca does not+        support direct messages, and this command will cause an error+        with that service.+      </para>+    </refsect2>++    <refsect2 id="twidge.commands.lsrecent">+      <title>lsrecent</title>+      <para>+        Lists recent posts made by you or the people you follow.+      </para>+    </refsect2>++    <refsect2 id="twidge.commands.lsreplies">+      <title>lsreplies</title>+      <para>+        Lists recent replies made by anyone on the microblogging site+        to you.+      </para>+    </refsect2>+  </refsect1>++  <refsect1 id="twidge.commands.displayinfo">+    <title>Commands to Display Other Information</title>+    <para>+      These commands honor --all and --long like the other commands,+      but do not honor --saveid or --unseen, as these options make no+      sense.+    </para>++    <refsect2 id="twidge.commands.lsfollowers">+      <title>lsfollowers</title>+      <cmdsynopsis>+        <command>twidge lsfollowers</command>+        <arg choice="opt"><replaceable>options</replaceable></arg>+        <arg choice="opt"><replaceable>username</replaceable></arg>+      </cmdsynopsis>+      <para>+        Will slow a list of people following you.  If given an+        optional username, shows the people that follow that user.  If+        given --long, shows the IDs for each person.  You may need to+        use --all to get a complete list, but again this may generate+        significant traffic.+      </para>+    </refsect2>++    <refsect2 id="twidge.commands.lsfollowing">+      <title>lsfollowing</title>+      <cmdsynopsis>+        <command>twidge lsfollowing</command>+        <arg choice="opt"><replaceable>options</replaceable></arg>+        <arg choice="opt"><replaceable>username</replaceable></arg>+      </cmdsynopsis>+      <para>+        Shows a list of the people you follow.  Arguments and actions+        are the same as with lsfollowers.+      </para>+    </refsect2>+  </refsect1>++  <refsect1 id="twidge.commands.action">+    <title>Action Commands</title>+    <para>+      These commands perform an action on the server.+    </para>+++    <refsect2 id="twidge.commands.dmsend">+      <title>dmsend</title>+      <cmdsynopsis>+        <command>twidge dmsend</command>+        <arg choice="plain"><replaceable>recipient</replaceable></arg>+        <arg choice="opt"><replaceable>status</replaceable></arg>+      </cmdsynopsis>+      <para>+        Causes &twidge; to send a new direct message to the designated+        recipient.  If a+        status is given on the command line, it must be presented as a+        single argument to &twidge; by the use of shell quoting if+        needed.  If no status is given on the command line, a single+        line will be read from stdin and used as the status.+      </para>+      <para>+        The maximum length of updates on various microblogging sites+        is 140 characters.  Twidge will abort with an error if your+        update attempt exceeds that length.+      </para>+      <para>+        By default, Twidge will attempt to shorten URLs in your+        updates via the TinyURL.com service.  You can disable this by+        setting shortenurls = no in the [DEFAULT] or [dmsend] section of your+        configuration file.+      </para>+    </refsect2>++    <refsect2 id="twidge.commands.follow">+      <title>follow</title>+      <cmdsynopsis>+        <command>twidge follow</command>+        <arg choice="plain"><replaceable>username</replaceable></arg>+      </cmdsynopsis>+      <para>+        This command will cause &twidge; to request that the+        microblogging site add the given username to the list of+        people you follow.  It is considered an error to attempt to+        add someone you already follow.+      </para>+    </refsect2>++    <refsect2 id="twidge.commands.setop">+      <title>setup</title>+      <cmdsynopsis><command>twidge setup</command></cmdsynopsis>+      <para>+        Enters the interactive first-time setup tool.+      </para>+    </refsect2>++    <refsect2 id="twidge.commands.unfollow">+      <title>unfollow</title>+      <cmdsynopsis>+        <command>twidge unfollow</command>+        <arg choice="plain"><replaceable>username</replaceable></arg>+      </cmdsynopsis>+      <para>+        This command will cause &twidge; to request that the+        microblogging site remove the given username from the list of+        people you follow.  It is considered an error to attempt to+        remove someone you do not follow.+      </para>+    </refsect2>++    <refsect2 id="twidge.commands.update">+      <title>update</title>+      <cmdsynopsis>+        <command>twidge update</command>+        <arg choice="opt"><replaceable>status</replaceable></arg>+      </cmdsynopsis>+      <cmdsynopsis>+        <command>twidge update -r</command>+      </cmdsynopsis>+      <para>+        Causes &twidge; to post a new status to the server.  If a+        status is given on the command line, it must be presented as a+        single argument to &twidge; by the use of shell quoting if+        needed.  If no status is given on the command line, a single+        line will be read from stdin and used as the status.+      </para>+      <para>+        The maximum length of updates on various microblogging sites+        is 140 characters.  Twidge will abort with an error if your+        update attempt exceeds that length.+      </para>+      <para>+        By default, Twidge will attempt to shorten URLs in your+        updates via the TinyURL.com service.  You can disable this by+        setting shortenurls = no in the [DEFAULT] or [update] section of your+        configuration file.+      </para>+      <para>+        When -r is given, &twidge; expects to read an RFC2822 email+        message in stdin.  The body of the message will be used as the+        content of the update.  The References header of the message+        will be briefly scanned, and if appropriate, the reply-to+        attribute of the update will reflect the Message-ID referred+        to therein.  This way, if you use <command>twidge lsrecent+        --mailto</command> to email recent items to you, then use your+        email reply button to reply to them, &twidge; will link the+        two on Twitter.  This linkage can be done even if you omit+        @reply, but will likely confuse many people because most other+        clients can't do this.  You should still include @reply.+      </para>+      <para>+        It should be noted that, in an effort to minimize size and+        complexity, &twidge; has an extremely simple email parser.+        You should send it only plain text messages.  Do not use HTML,+        RTF, attachments, or anything that would cause MIME headers to+        appear in the RFC2822 body.  You probably want to turn off+        your signature as well. &twidge; will convert newline+        characters to spaces when processing your message body.  +      </para>+    </refsect2>+  </refsect1>++  <refsect1 id="twidge.commands.other">+    <title>Other Command</title>+    +    <refsect2 id="twidge.commands.lscommands">+      <indexterm><primary>Commands</><secondary>lscommands</></>+      <title>lscommands</title>+      <cmdsynopsis><command>twidge lscommands</command></cmdsynopsis>+      <para>+        This command will display a list of all available &twidge;+        commands along with a brief description of each.+      </para>+    </refsect2>+  </refsect1>++  <refsect1 id="twidge.config">+    <title>twidge Configuration File</title>+    <para>+      &twidge; has a configuration file in which you can set various+      options.  This file normally lives under+      <filename>~/.twidgerc</filename>.+    </para>+    <para>+      The configuration file has multiple sections.  Each section has+      a name and is introduced with the name in brackets.  Each+      section has one or more options.+    </para>+    <para>+      The section named DEFAULT is special in that it provides+      defaults that will be used whenever an option can't be found+      under a different section.  If you specify no section names,+      DEFAULT is the assumed section.  Some items, such as username,+      password, and urlbase are assumed to be in DEFAULT.+    </para>+    <para>+      Let's start by looking at an example file, and then proceed to+      examine all the options that are available.+    </para>+    <programlisting><![CDATA[+[DEFAULT]++; Username and password+username = ilovetwidge++password = secret++; If your password contains a percent sign (%), list it twice (%%)++; Path to server API interface -- no trailing slash+urlbase = https://twitter.com++shortenurls = yes++; Last IDs seen by different commands.  Written to with -s.++[lsarchive]+lastid = 917383569++[lsrecent]+lastid = 914881241+]]></programlisting>+    <para>+      Whenever &twidge; looks for information about a particular+      option, it first checks to see if it can find that option in a+      section for that option.  If not, it checks the+      <option>DEFAULT</option> section.  If it still doesn't find an+      answer, it consults its built-in defaults.  The only built-in+      default at present is urlbase.+    </para>+    <refsect2 id="twidge.config.general">+      <title>General Options</title>+      <para>These are specified in the <option>DEFAULT</option>+        section.+      </para>+      <variablelist>+        <varlistentry><term>username</term>+          <listitem><para>+              Your username on the microblogging site.  No default.+            </para></listitem>+        </varlistentry>+        <varlistentry><term>password</term>+          <listitem><para>+              Your password on the microblogging site.  No default.+            </para></listitem>+        </varlistentry>+        <varlistentry><term>urlbase</term>+          <listitem><para>+              The URL to access the API of the microblogging site.+              The default, <literal>https://twitter.com</literal> is+              for Twitter.  To use Identica, you would specify+              <literal>http://identi.ca/api</literal>.  Do not put a+              trailing slash on this option.+            </para></listitem>+        </varlistentry>+      </variablelist>+    </refsect2>              ++    <refsect2 id="twidge.config.options">+      <title>Per-Command Options</title>+      <para>+        These options may be specified in <option>DEFAULT</option> or+        in a per-option section.  If placed in+        <option>DEFAULT</option>, they will apply to all relevant options+        unless overridden.+      </para>+      <variablelist>+        <varlistentry><term>lastid</term>+          <listitem><para>+              Stores the last ID seen for commands that support -s or+          -u.+            </para></listitem>+        </varlistentry>++        <varlistentry><term>mailfrom</term>+          <listitem><para>+              Gives the email address to use for the From: header on+              messages generated by &twidge;.  Normally specified in+              [DEFAULT] so as to impact all commands.  If not given, +              &twidge; specifies no From: line, leaving the system's+              mail transport to assign a default one.+            </para>+            <para>+              Should contain a bare email address only -- no brackets,+              parens, quotes, or comments.+            </para>+            <para>+              When given, Twidge uses the nickname and this address+              for the From line.  When not given, the nickname is+              prepended to the Subject line.+            </para>+          </listitem>+        </varlistentry>++        <varlistentry><term>sendmail</term>+          <listitem><para>+              Stores the path to the sendmail executable on your+              system, used for sending mail.  Normally specified in+              [DEFAULT] so as to impact all commands.  Defaults to+              /usr/sbin/sendmail.+            </para></listitem>+        </varlistentry>+        +        <varlistentry><term>shortenurls</term>+          <listitem>+            <para>+              You may specify <literal>shortenurls</literal> in the+              <literal>[update]</literal> section.  It defaults to yes.  If+              set to no, will cause &twidge; to omit its attempt to shorten+              URLs in your updates via <literal>tinyurl.com</literal>.+            </para>+          </listitem>+        </varlistentry>++      </variablelist>++    </refsect2>++  </refsect1>+              ++  <refsect1 id="twidge.tips">+    <title>Tips & Hints</title>+    <para>+      Here are a few tips and hints to make &twidge; more pleasant+      for you.+    </para>+    <refsect2 id="twidge.tips.proxy">+      <title>Going Through a Proxy</title>+      <para>+        If your connections must go through a proxy, you'll need to+        set an environment variable.+        If you use an+        environment variable, your settings may will also impact other+        applications -- and that's probably what you want.  See the+        Environment section later for tips on doing that.+      </para>+    </refsect2>++  </refsect1>++  <refsect1 id="twidge.environment">+    <title>Environment</title>+    <para>+      &twidge; does not read any environment variables directly.+      However, it does pass on the environment to the+      programs it calls, such as Curl.  This can be useful for+      specifying proxies.  Please see+      <application>curl</application>(1) for more details.+    </para>+  </refsect1>++  <refsect1 id="twidge.conforming">+    <title>Conforming To</title>+    <itemizedlist>+      <listitem><para>The <ulink+      url="http://www.w3.org/XML/">Extensible Markup Language+            (XML)</ulink> standard (W3C)</para></listitem>+      </itemizedlist>+  </refsect1>++  <refsect1 id="twidge.copyright">+    <title>Copyright</title>+    <indexterm><primary>Copyright</></>+    <para>+      &twidge;, all code, documentation, files, and build scripts are+      Copyright &copy; 2006-2008 John Goerzen.  All code, documentation,+      sripts, and files are under the following license unless+      otherwise noted:+    </para>+    <para>+      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.+    </para>+    +    <para>+      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.+    </para>+    +    <para>+      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 St, Fifth Floor, Boston, MA  02110-1301  USA+    </para>+    <para>+      The GNU General Public License is available in the file COPYING+      in the source distribution.  Debian GNU/Linux users may find this in+      /usr/share/common-licenses/GPL-2.+    </para>+    <para>+      If the GPL is unacceptable for your uses, please e-mail me; alternative+      terms can be negotiated for your project.+    </para>+  </refsect1>+  +  <refsect1 id="twidge.author">+    <title>Author</title>+    <para>+      &twidge;, its modules, documentation, executables, and all+      included files, except where noted, was written by+      John Goerzen <email>jgoerzen@complete.org</email> and+      copyright is held as stated in the COPYRIGHT section.+    </para>+  </refsect1>++  <refsect1 id="twidge.seealso">+    <title>See Also</title>+    <para>+      <application>curl</application>(1)+    </para>+    <para>+      The &twidge; homepage at <ulink+      url="http://software.complete.org/twidge"></>.+    </para>+  </refsect1>+  +  </refentry>
+ doc/twidge.sgml view
@@ -0,0 +1,20 @@+<!DOCTYPE reference PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [+  <!ENTITY index SYSTEM "index/index.sgml">+  <!ENTITY man.twidge SYSTEM "twidge-manpage.sgml">+  <!ENTITY twidge "<application>twidge</application>">++]>++  <reference>+    <title>twidge Manual</title>+     &man.twidge;+  </reference>++<!--+Local Variables:+mode: sgml+sgml-set-face: T+End:++-->+
+ twidge.cabal view
@@ -0,0 +1,52 @@+Name: twidge+Version: 0.99.0+License: GPL+Maintainer: John Goerzen <jgoerzen@complete.org>+Author: John Goerzen+Stability: Stable+Copyright: Copyright (c) 2006-2008 John Goerzen+license-file: COPYRIGHT+extra-source-files: COPYING, INSTALL, doc/SConstruct,+  doc/twidge-manpage.sgml, doc/twidge.sgml, doc/local.dsl,+  doc/man.twidge.sgml, doc/printlocal.dsl, doc/sgml-common/COPYING,+  doc/sgml-common/COPYRIGHT, doc/sgml-common/ChangeLog,+  doc/sgml-common/Makefile.common, doc/sgml-common/SConstruct,+  doc/sgml-common/ps2epsi+homepage: http://software.complete.org/twidge+Build-type: Simple+Category: Network+Synopsis: Unix Command-Line Twitter and Identica Client+Description: twidge is a client for microblogging sites such as Twitter and+ Identica (identi.ca). Microblogging sites let you post short+ one-paragraph updates, follow the updates that your friends post, and+ interact with everyone in the site in a conversation style.+ .+ twidge is a client to make working with microblogging sites faster+ and easier. It is extremely versatile, and can be customized to work+ the way you want to work, and combined with other tools to do just+ about anything.+ .+ twidge can be used quite nicely interactively from the shell. It is+ useful directly as-is, and with simple shell aliases can make a+ highly efficient system to do exactly what you want. It is perfectly+ capable of being your only client for microblogging.+ .+ twidge also can be used in an automated way, via cron(1), or it can+ even integrate with your email system.+ .+ A full list of twidge features, along with numerous suggestions on+ how to use it, can be found at the twidge website at+ http://software.complete.org/twidge.++Build-Depends: network, unix, parsec, MissingH>=1.0.0,+ mtl, base, HaXml>=1.13.2, HaXml<1.19, hslogger,+ ConfigFile, directory, HSH, Cabal, regex-posix++Executable: twidge+Main-Is: twidge.hs+Other-Modules: Commands, Config, Download, FeedParser,+        Types, Utils, +        Commands.Ls+GHC-Options: -O2+Extensions: ExistentialQuantification, OverlappingInstances,+    UndecidableInstances
+ twidge.hs view
@@ -0,0 +1,89 @@+{- component+Copyright (C) 2006-2008 John Goerzen <jgoerzen@complete.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+-}++{- |+   Module     : Main+   Copyright  : Copyright (C) 2006-2008 John Goerzen+   License    : GNU GPL, version 2 or above++   Maintainer : John Goerzen <jgoerzen@complete.org>+   Stability  : provisional+   Portability: portable++Written by John Goerzen, jgoerzen\@complete.org++-}++import Config+import System.Log.Logger+import System.Log.Handler.Simple+import System.Console.GetOpt.Utils+import System.Console.GetOpt+import System.Environment+import Data.List+import System.Exit+import Commands+import Types+import Control.Monad+import Data.ConfigFile(emptyCP)+import System.IO+import Paths_twidge(version)+import Data.Version++main = +    do updateGlobalLogger "" (setLevel INFO)+       argv <- getArgs+       +       case getOpt RequireOrder options argv of+         (o, n, []) -> worker o n+         (_, _, errors) -> usageerror (concat errors) -- ++ usageInfo header options)+       +options = [Option "d" ["debug"] (NoArg ("d", "")) "Enable debugging",+           Option "c" ["config"] (ReqArg (stdRequired "c") "FILE")+                  "Use specified config file",+           Option "" ["help"] (NoArg ("help", "")) "Display this help"]++worker args commandargs =+    do when (lookup "help" args == Just "") $ usageerror ""+       when (lookup "d" args == Just "") +            (updateGlobalLogger "" (setLevel DEBUG))+       handler <- streamHandler stderr DEBUG -- stdout has issues with HSH+       updateGlobalLogger "" (setHandlers [handler])+       let commandname = head cmdargs+       case lookup commandname allCommands of+         Just command -> +             do cp <- if commandname `elem` ["lscommands", "setup"] -- no config file needed+                      then return emptyCP+                      else loadCP (lookup "c" args)+                execcmd command (tail cmdargs) (lookup "c" args) cp+         Nothing -> usageerror ("Invalid command name " ++ commandname)+       where cmdargs = case commandargs of+                         [] -> ["help"]+                         x -> x++usageerror errormsg =+    do putStrLn errormsg+       putStrLn (usageInfo header options)+       putStrLn "Run \"twidge lscommands\" for a list of available commands.\n\+                \Run \"twidge command --help\" for help on a particular command.\n"+       putStr $ "This is Twidge, version " ++ showVersion version+       putStrLn $ ".  Copyright (c) 2008 John Goerzen"+       exitFailure++header = "Usage: twidge [global-options] command [command-options]\n\n\+         \Available global-options are:\n"