twidge/0000755000000000000000000000000012351342375007234 5ustar twidge/twidge-sh0000755000000000000000000000452411461424336011061 0ustar #!/bin/bash # twidge-sh: customized interactive twidge shell # Copyright: (C) 2010 Florian Baumann # License: GPL-3 # Date: Monday 2010-10-04 ### initial settings & security ############################################### # need some general security checks and generate settings # # get config if available if [ -r $HOME/.twidgerc ]; then twidgerc=$HOME/.twidgerc else echo "$HOME/.twidgerc not found!" echo "try: 'twidge setup' to fix it." exit fi # check username if ! grep -q "screen_name" $twidgerc ; then echo "error by getting username from $twidgerc"; exit 1 fi # check service if ! grep -q -e "^urlbase:.*$" $twidgerc ; then echo "error by getting microblogging-service from $twidgerc"; exit 1 fi # create new shell with specific config [ "$0" = 'bash' ] || exec /usr/bin/env bash --rcfile "$0" "$@" # include user's .bashrc file [ -r ~/.bashrc ] && { pushd ~ > /dev/null . .bashrc popd > /dev/null } ### completion and aliases #################################################### # read standard commands and create aliases for new prompt # defined aliases will automatically be completed # usage: # user@twitter> lsrecent # for x in $(twidge lscommands | tail --lines=+4 | cut -f1 -d' '| grep "^$cur") do alias $x="twidge $x" done # read local aliases in .twidgerc # for example: # [alias] # recent: lsrecent -u # replies: lsreplies -u # OLDIFS=$IFS; IFS=$'\n' for y in $(cat $twidgerc | sed -n -e '/\[alias\]/,/\[.*\]/s/:/:/p') do key=$(echo $y | cut -d : -f 1) command=$(echo $y | cut -d : -f 2-) alias ${key}="twidge $command" done IFS=$OLDIFS # display commands by "help" alias help="twidge lscommands" ### customized prompt ######################################################### # create microblogging prompt # for example: user@twitter> # PS1='$(get_user)@$(get_services)> ' # get username from config get_user() { if fgrep -q "screen_name" $twidgerc ; then fgrep "screen_name" $twidgerc | cut -d \" -f 8 elif fgrep -q "username:" $twidgerc; then fgrep "username:" | awk '{print $NF}' fi } # get configured service for prompt get_services() { if grep -q -e "^urlbase:.*twitter.com$" $twidgerc; then echo "twitter" elif grep -q -e "^urlbase:.*identi.ca$" $twidgerc; then echo "identica" fi } twidge/TODO0000644000000000000000000000010411401534175007713 0ustar support for more secure curl stuff (netrc) Prettier error handling twidge/OAuth.hs0000644000000000000000000000613712156620144010613 0ustar {- hpodder component Copyright (C) 2010 John Goerzen 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 : OAuth Copyright : Copyright (C) 2010 John Goerzen License : GNU GPL, version 2 or above Maintainer : John Goerzen Stability : provisional Portability: portable Written by John Goerzen, jgoerzen\@complete.org -} module OAuth where import Network.OAuth.Consumer import Data.Maybe import Network.OAuth.Http.Request import Network.OAuth.Http.HttpClient import Data.ConfigFile import Utils import Data.Either.Utils obfuscatedTwitterKeys = ("jRlf9pXnU7uEV5ZcxrJmc", "L17bXFykkLYz4TBCmet1wuX9VtXbLq8Xj4Lif42O4ew") identicaKeys = ("f027d666f9d0e7b80beaed528aec473c", "d84c9b3dafb14becb5e05a002886b60c") twitterKeys = (twitterDeObfuscator (fst obfuscatedTwitterKeys), twitterDeObfuscator (snd obfuscatedTwitterKeys)) twitterDeObfuscator :: String -> String twitterDeObfuscator = reverse . map rot13 instance Show Application where show (Application a b c) = "Application " ++ show a ++ " " ++ show b ++ " " ++ show c instance Show Token where show (TwoLegg app oauthp) = "TwoLegg " ++ show app ++ " " ++ show oauthp show (ReqToken app oauthp) = "ReqToken " ++ show app ++ " " ++ show oauthp show (AccessToken app oauthp) = "AccessToken " ++ show app ++ " " ++ show oauthp rot13 :: Char -> Char rot13 x = case lookup x trans of Just y -> y Nothing -> x where trans = zip (lcbase ++ ucbase) (part lcbase ++ part ucbase) lcbase = ['a' .. 'z'] ucbase = ['A' .. 'Z'] part x = drop 13 x ++ take 13 x getDefaultKeys :: ConfigParser -> Maybe (String, String) getDefaultKeys cp = case serverHost cp of "api.twitter.com" -> Just twitterKeys "twitter.com" -> Just twitterKeys "identi.ca" -> Just identicaKeys getApp :: ConfigParser -> Maybe Application getApp cp = if (has_option cp "DEFAULT" "oauthconsumerkey" && has_option cp "DEFAULT" "oauthconsumersecret") then Just $ Application {consKey = forceEither $ get cp "DEFAULT" "oauthconsumerkey", consSec = forceEither $ get cp "DEFAULT" "oauthconsumersecret", callback = OOB} else case getDefaultKeys cp of Just (k, s) -> Just $ Application {consKey = k, consSec = s, callback = OOB} Nothing -> Nothing twidge/Setup.lhs0000644000000000000000000000015011401534175011034 0ustar #!/usr/bin/env runhugs arch-tag: Main setup script > import Distribution.Simple > main = defaultMain twidge/Commands.hs0000644000000000000000000000433212156620144011327 0ustar {- Copyright (C) 2006-2008 John Goerzen 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-2010 John Goerzen License : GNU GPL, version 2 or above Maintainer : John Goerzen Stability : provisional Portability: portable Written by John Goerzen, jgoerzen\@complete.org -} module Commands where import Text.Printf import Utils import Types import qualified Commands.FollowBlock import qualified Commands.Ls import qualified Commands.Setup import qualified Commands.Update --allCommands :: [(String, Command)] allCommands = [Commands.Update.dmsend, Commands.FollowBlock.block, Commands.FollowBlock.follow, Commands.Ls.lsarchive, lscommands, Commands.Ls.lsdm, Commands.Ls.lsdmarchive, Commands.Ls.lsblocking, Commands.Ls.lsfollowers, Commands.Ls.lsfollowing, Commands.Ls.lsrecent, Commands.Ls.lsreplies, Commands.Ls.lsrtreplies, Commands.Ls.status, Commands.Setup.setup, Commands.FollowBlock.unblock, Commands.FollowBlock.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 twidge/debian/0000755000000000000000000000000012351342322010446 5ustar twidge/debian/rules0000755000000000000000000000333111511511726011531 0ustar #!/usr/bin/make -f # -*- makefile -*- # Sample debian/rules that uses debhelper. # This file was originally written by Joey Hess and Craig Small. # As a special exception, when this file is copied by dh-make into a # dh-make output file, you may use that output file without restriction. # This special exception was added by Craig Small in version 0.37 of dh-make. # Uncomment this to turn on verbose mode. #export DH_VERBOSE=1 CFLAGS = -Wall -g ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif configure: configure-stamp configure-stamp: dh_testdir # Add here commands to configure the package. touch configure-stamp build: build-stamp build-stamp: configure-stamp dh_testdir # Add here commands to compile the package. $(MAKE) cp -r doc debian/tmp-doc cd debian/tmp-doc && scons pdf cd debian/tmp-doc && scons manpages #docbook-to-man debian/twidge.sgml > hpodder.1 touch $@ clean: dh_testdir dh_testroot rm -f build-stamp configure-stamp dh_auto_clean -- clean-code # -$(MAKE) clean-code -rm -rf debian/tmp-doc dh_clean install: build dh_testdir dh_testroot dh_prep dh_installdirs cp dist/build/twidge/twidge debian/twidge/usr/bin/ dh_install # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot dh_installchangelogs dh_installdocs dh_installexamples dh_installman debian/tmp-doc/twidge.1 dh_link dh_strip dh_compress dh_fixperms dh_installdeb dh_shlibdeps dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure twidge/debian/control0000644000000000000000000000357112156620144012063 0ustar Source: twidge Section: utils Priority: optional Maintainer: John Goerzen Build-Depends: debhelper (>= 7), groff, docbook-utils, jade, lynx, scons, poppler-utils, sgml2x, gtk-doc-tools, ghc (>= 6.8.2), haskell-devscripts (>= 0.6.6), libghc-missingh-dev (>= 1.0.0), libghc-network-dev, libghc-unix-dev, libghc-mtl-dev, libghc-aeson-dev (>= 0.6.1.0), libghc-filepath-dev, libghc-configfile-dev (>= 1.0.4.5), libghc-hslogger-dev (>= 1.0.7.1), libghc-regex-posix-dev, libghc-utf8-string-dev, libghc-hsh-dev (>= 1.2.6.3), libghc-hoauth-dev Standards-Version: 3.9.1 Homepage: https://github.com/jgoerzen/twidge/wiki/ Vcs-Browser: https://github.com/jgoerzen/twidge Vcs-Git: git://github.com/jgoerzen/twidge.git Package: twidge Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, ${haskell:Depends}, curl Description: Unix Command-Line Twitter and Identica Client 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. twidge/debian/docs0000644000000000000000000000003211401534175011320 0ustar debian/tmp-doc/twidge.pdf twidge/debian/compat0000644000000000000000000000000211401534175011650 0ustar 5 twidge/debian/changelog0000644000000000000000000001172612351342322012327 0ustar twidge (1.1.2) unstable; urgency=medium * Fix mail generation for tweets containing \n. -- John Goerzen Sat, 21 Jun 2014 12:45:34 -0500 twidge (1.1.1) unstable; urgency=medium * Relax aeson upper bound. Closes: #746110. -- John Goerzen Sat, 21 Jun 2014 10:54:29 -0500 twidge (1.1.0) unstable; urgency=low * Update to new twitter API. Thanks to Adam Fitzpatrick for the patch. Closes: #712223, #632259. * Updated to newer hoauth. Now buildable in sid again. -- John Goerzen Fri, 14 Jun 2013 00:30:27 -0500 twidge (1.0.9) unstable; urgency=low * Correctly handle UTF-8 updates given on the command line. Closes: #611775. * Correct VCS and homepage URLs. -- John Goerzen Sat, 05 Feb 2011 13:26:51 -0600 twidge (1.0.8.1+nmu1) unstable; urgency=low * Non-maintainer upload. * Fix build deps to refer to ghc instead of ghc6 (Closes: #629725) * Work on newer HaXml in Debian -- Iain Lane Thu, 28 Jul 2011 13:15:31 +0100 >>>>>>> debnmu twidge (1.0.8.1) unstable; urgency=low * Clean up a debian packaging bug introduced in 3rd-party commit 880982d2bc2a9dbbff2893fa16ceb04ce32f6356. Package now contains all the files it should again. Closes: #609139. -- John Goerzen Thu, 06 Jan 2011 22:17:54 -0600 twidge (1.0.8) unstable; urgency=low * Accept parens as part of URLs. CLoses: #608978. -- John Goerzen Wed, 05 Jan 2011 00:12:38 -0600 twidge (1.0.6) unstable; urgency=low * Twitter invalidated the twidge API key because it became publicly known (sigh). Have now obfuscated it enough for them. twidge will be broken by default without this fix. Closes: #601427. -- John Goerzen Mon, 25 Oct 2010 20:28:16 -0500 twidge (1.0.5) unstable; urgency=high * Twitter has dropped support for http://twitter.com URLs on some servers, and now generally requires http://api.twitter.com/1. This required some minor changes to configuration code. Twitter uses geoIP and some of there servers work fine with 1.0.2 while others don't. This version will work with all of them. -- John Goerzen Wed, 01 Sep 2010 00:09:38 -0500 twidge (1.0.2) unstable; urgency=high * Corrected bug in 1.0.1 that prevented any updates from posting properly. * Fixed the withBitly flag support. -- John Goerzen Thu, 03 Jun 2010 00:08:34 -0500 twidge (1.0.1) unstable; urgency=medium * New upstream release. * Twitter is dropping support for HTTP basic auth. Versions of twidge prior to 1.0.0 will soon fail to work. This version switches using oAuth to maintain compatibility. Users will need to re-run twidge setup to complete the switch. + Code relevant to #521616 has been removed. Closes: #521616. + New HTTP client in place. Closes: #535766. * New commands to support new-style retweets: lsrt, lsrtreplis, lsrtarchive. Closes: #583999. * lsarchive gained -U to let you specify which user's posts to see. * New support for URL shorteners: is.gd, bit.ly, j.mp. Patch from Robin Green. * Added --width option to ls commands. Patch from Robin Green. * Corrected a spelling mistake. Closes: #521616. * Added support for blocking and unblocking. * Only shorten URLs when needed. Patch from Eric Y. Kow. Closes: #567174. * Added support to set an in_reply_to_status_id via the -i argument to update. * Provide correct UTF-8 output. * New config file options: savelast, alias section, oauth-related URLs, * Added bash completion script from Ernesto Hernández-Novich. * ACK NMU. Closes: #550657. -- John Goerzen Wed, 02 Jun 2010 03:34:01 -0500 twidge (0.99.4+nmu1) unstable; urgency=low * Non-maintainer upload needed to address xpdf's RC bugs: * Perform the PDF generation with pdftotext from poppler-utils instead of xpdf-utils (Closes: #550657) -- Moritz Muehlenhoff Mon, 02 Nov 2009 22:28:23 +0100 twidge (0.99.4) unstable; urgency=low * Added build-dep on libghc6-hsh-dev. Closes: #506543. * Tightened build-deps. -- John Goerzen Thu, 11 Dec 2008 03:33:17 -0600 twidge (0.99.3) unstable; urgency=low * Added official "source" paramter from Twitter. -- John Goerzen Sun, 14 Sep 2008 22:10:07 -0500 twidge (0.99.2) unstable; urgency=low * Now properly outputs UTF-8 strings for Unicode characters. * Removed incompatibility with newer Cabal versions. -- John Goerzen Sat, 13 Sep 2008 09:21:12 -0500 twidge (0.99.1) unstable; urgency=low * Fixed a logic bug that made -su options not work after the first time. -- John Goerzen Sat, 13 Sep 2008 08:45:24 -0500 twidge (0.99.0) unstable; urgency=low * Initial release. -- John Goerzen Wed, 02 Jul 2008 10:28:15 -0500 twidge/debian/copyright0000644000000000000000000000625412156620144012414 0ustar This package was debianized by John Goerzen It was downloaded from http://software.complete.org/twidge Upstream Author: John Goerzen Copyright (C) 2006-2013 John Goerzen 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. ---------------------------------------------------------------------- Two small functions, wrapText and wrapLines, in Utils.hs were copied from Cabal 1.4.0.2. It bears this license: Copyright (c) 2003-2007, Isaac Jones, Simon Marlow, Martin Sjögren, Bjorn Bringert, Krasimir Angelov, Malcolm Wallace, Ross Patterson, Ian Lynagh, Duncan Coutts, Thomas Schilling All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Isaac Jones nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. twidge/debian/dirs0000644000000000000000000000003611510672125011334 0ustar usr/bin etc/bash_completion.d twidge/COPYING0000644000000000000000000004310511401534175010266 0ustar 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. Copyright (C) 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. , 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. twidge/twidge.hs0000644000000000000000000000712411401721167011052 0ustar {- component Copyright (C) 2006-2008 John Goerzen 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 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,get) 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"] expandAlias cp cmd = either (const cmd) id $ get cp "alias" cmd 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 cp <- if commandname `elem` ["lscommands", "setup"] -- no config file needed then loadCP True (lookup "c" args) else loadCP False (lookup "c" args) let cmdargs' = (words $ expandAlias cp commandname) ++ (tail cmdargs) let commandname' = head cmdargs' case lookup commandname' allCommands of Just command -> execcmd command (tail cmdargs') (lookup "c" args) cp Nothing -> if commandname == commandname' then usageerror ("Invalid command name " ++ commandname) else usageerror ("Invalid command name " ++ commandname ++ " (aliased to " ++ 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-2010 John Goerzen" exitFailure header = "Usage: twidge [global-options] command [command-options]\n\n\ \Available global-options are:\n" twidge/Types.hs0000644000000000000000000000727612156620144010704 0ustar {-# LANGUAGE OverloadedStrings, CPP #-} {- hpodder component Copyright (C) 2006-2007 John Goerzen 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 Stability : provisional Portability: portable Written by John Goerzen, jgoerzen\@complete.org -} module Types where import Control.Applicative import Control.Monad (mzero) import Data.ConfigFile import Data.Aeson import Data.ByteString.Lazy (ByteString) import Data.List (isPrefixOf) import Data.String.Utils (strip) import Data.Text (unpack) decode_json :: FromJSON a => ByteString -> a decode_json = either error id . eitherDecode {- | Removes potentially problematic or malicious stuff -} sanitize :: String -> String sanitize = strip . map sanitizer where sanitizer c | c `elem` "\n\r\0\t" = ' ' | otherwise = c {- | Twitter has an additional level of escaping for < and > only. Sigh. -} unEsc :: String -> String unEsc [] = [] unEsc x | "<" `isPrefixOf` x = '<' : unEsc (drop 4 x) | ">" `isPrefixOf` x = '>' : unEsc (drop 4 x) | otherwise = head x : unEsc (tail x) 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) newtype TimelineMessage = TimelineMessage { fromTimeline :: Message } instance FromJSON TimelineMessage where parseJSON j = TimelineMessage <$> parseTimelineMessage j parseTimelineMessage (Object v) = Message <$> s v "id_str" <*> (v .: "user" >>= extractScreenName) <*> pure "" <*> retweetOrText v <*> s v "created_at" parseTimelineMessage _ = mzero newtype DirectMessage = DirectMessage { fromDM :: Message } instance FromJSON DirectMessage where parseJSON j = DirectMessage <$> parseDirectMessage j parseDirectMessage (Object v) = Message <$> s v "id_str" <*> s v "sender_screen_name" <*> s v "recipient_screen_name" <*> (unEsc <$> s v "text") <*> s v "created_at" parseDirectMessage _ = mzero extractScreenName (Object v) = s v "screen_name" extractScreenName _ = mzero retweetOrText v = unEsc <$> ((retweet v) <|> (unpack <$> v .: "text")) where retweet v = do rt <- v .: "retweeted_status" user <- rt .: "user" >>= extractScreenName text <- rt .: "text" return $ "RT @" ++ user ++ ": " ++ text s v name = sanitize <$> v .: name data UserList = UserList [ListedUser] (Maybe String) newtype ListedUser = ListedUser { fromListedUser :: (String, String) } instance FromJSON UserList where parseJSON (Object v) = UserList <$> v .: "users" <*> v .:? "next_cursor_str" parseJSON _ = mzero instance FromJSON ListedUser where parseJSON (Object v) = (ListedUser .) . (,) <$> v .: "screen_name" <*> v .: "id_str" parseJSON _ = mzero twidge/COPYRIGHT0000644000000000000000000000601411401721167010523 0ustar Copyright (C) 2006-2010 John Goerzen 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. ---------------------------------------------------------------------- Two small functions, wrapText and wrapLines, in Utils.hs were copied from Cabal 1.4.0.2. It bears this license: Copyright (c) 2003-2007, Isaac Jones, Simon Marlow, Martin Sjögren, Bjorn Bringert, Krasimir Angelov, Malcolm Wallace, Ross Patterson, Ian Lynagh, Duncan Coutts, Thomas Schilling All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Isaac Jones nor the names of other contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. twidge/twidge.cabal0000644000000000000000000000472112351342272011503 0ustar Name: twidge Version: 1.1.2 License: GPL Maintainer: John Goerzen Author: John Goerzen Stability: Stable Copyright: Copyright (c) 2006-2013 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, Makefile, twidge.bash_completion 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. Cabal-Version: >=1.2.3 Flag withBitly description: Enable bit.ly and j.mp shorteners (requires Bitly module) default: False Executable twidge Build-Depends: network, unix, parsec, MissingH>=1.0.0, mtl, base >= 4 && < 5, hslogger, hoauth>=0.3.4 && <0.4, ConfigFile, directory, HSH, regex-posix, utf8-string, binary, bytestring, curl, old-locale, time, aeson>=0.6.1.0, text>=0.11.2.0 && <0.12 if flag(withBitly) Build-Depends: Bitly CPP-OPTIONS: -DUSE_BITLY Main-Is: twidge.hs Other-Modules: Commands, Commands.FollowBlock, Commands.Ls, Commands.Setup, Commands.Update, Config, Download, MailParser, Types, Utils, OAuth GHC-Options: -O2 Extensions: ExistentialQuantification, OverlappingInstances, UndecidableInstances twidge/Commands/0000755000000000000000000000000012156620144010771 5ustar twidge/Commands/Ls.hs0000644000000000000000000004230712351342204011704 0ustar {- Copyright (C) 2006-2008 John Goerzen 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, lsblocking, lsfollowing, lsfollowers, lsarchive, lsrtreplies, status, lsdm, lsdmarchive) where import Utils import System.Log.Logger import Types import Text.Printf import System.Console.GetOpt import Download import Data.ConfigFile import Data.String.Utils(strip) import Config import Data.Either.Utils(forceEither) import Control.Monad(when) import HSH import System.Console.GetOpt.Utils import Network.URI import Data.Maybe (isJust, isNothing) import Network.OAuth.Http.Request import Data.Time.Format (formatTime, parseTime) import Data.Time.LocalTime (ZonedTime) import System.Locale (defaultTimeLocale, rfc822DateFormat) i = infoM "ls" defaultWidth = 80 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", widthopt] widthopt = Option "w" ["width"] (ReqArg (stdRequired "w") "WIDTH") ("Set the margin at which word-wrapping occurs.\n\ \Ignored in long format mode. Default is " ++ show defaultWidth ++ ".") 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"] maybeSaveList section cpath cp args [] = return () maybeSaveList section cpath cp args newids = do debugM section $ "maybeSaveList called for " ++ section ++ ": " ++ show args ++ " " ++ show newids maybeSave section cpath cp args theid where theid = maximum . map (read::String -> Integer) $ newids maybeSave section cpath cp args newid = let sArg = isJust $ lookup "s" args sConf = isRight True $ get cp "DEFAULT" "savelast" in case (any id [sArg,sConf], get cp section "lastid") of (False, _) -> do debugM "maybeSave" "maybeSave: No -s nor savelast" return () (True, Left _) -> do debugM "maybeSave" "maybeSave: Will add ID" saveid (True, 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 isRight _ (Left _) = False isRight v1 (Right v2) = v1 == v2 sinceArgs section cp args maxId = from ++ since where from = maybe [] (\i -> [("max_id", show i)]) maxId since = case (lookup "u" args, get cp section "lastid") of (Nothing, _) -> [] (_, Left _) -> [] (_, Right a) -> [("since_id", strip a)] screenNameArgs args = case lookup "U" args of Nothing -> [] Just username -> [("screen_name", username)] -------------------------------------------------- -- lsrecent & friends -------------------------------------------------- lsrecent = simpleCmd "lsrecent" "List recent updates from your home timeline" lsrecent_help (stdopts ++ sinceopts) (paginated (statuses_worker "lsrecent" "/statuses/home_timeline")) lsreplies = simpleCmd "lsreplies" "List recent messages mentioning you" lsreplies_help (stdopts ++ sinceopts) (paginated (statuses_worker "lsreplies" "/statuses/mentions_timeline")) lsarchive = simpleCmd "lsarchive" "List recent status updates you posted yourself" lsarchive_help (stdopts ++ sinceopts ++ usernameopts) (paginated (statuses_worker "lsarchive" "/statuses/user_timeline")) where usernameopts = [ Option "U" ["username"] (ReqArg (stdRequired "U") "USERNAME") "Instead of showing your own updates, show\n\ \those of the given username." ] status = simpleCmd "status" "Retrieve a single status" status_help [widthopt] status_worker 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")) lsrtreplies = simpleCmd "lsrtreplies" "List others' retweets of your statuses" lsrtreplies_help (stdopts ++ sinceopts) (paginated (statuses_worker "lsrtreplies" "/statuses/retweets_of_me")) statuses_worker = generic_worker handleStatuses dm_worker = generic_worker handleDM status_worker _ cp (args, [statusId]) = do json <- sendAuthRequest GET cp "/statuses/show.json" [("id", statusId)] [] debugM "status" $ "Got doc: " ++ show json let TimelineMessage status = decode_json json printStatus "status" cp args status status_worker _ _ _ = error "Invalid args to status; see twidge status --help" handleStatuses = handleGeneric (map fromTimeline) printStatus generic_worker procfunc section command cpath cp (args, _) maxId = do json <- sendAuthRequest GET cp (command ++ ".json") (sinceArgs section cp args maxId ++ screenNameArgs args) [] debugM section $ "Got doc: " ++ show json results <- procfunc section cp args json when (isNothing maxId) $ maybeSaveList section cpath cp args (map sId results) return (results, nextMaxId results) nextMaxId :: [Message] -> Maybe Integer nextMaxId [] = Nothing nextMaxId r = Just ((minimum $ map (read . sId) r) - 1) status_help = "Usage: twidge status [options] status-id\n" lsrecent_help = "Usage: twidge lsrecent [options]\n\n\ \You can see the 20 most recent items from your timeline 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 @mentions from others of you with:\n\n\ \ twidge lsreplies\n\n\ \For more examples, including how to see only unseen mentions, 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" lsrtreplies_help = "Usage: twidge lsrtreplies [options]\n\n\ \You can see the 20 most retweets made of your statuses with:\n\n\ \ twidge lsrtreplies\n\n\ \For more examples, including how to see only unseen retweets, please\n\ \refer to the examples under twidge lsrecent --help, which also pertain\n\ \to lsreplies.\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" handleDM = handleGeneric (map fromDM) printDM handleGeneric pfunc printfunc section cp args json = let statuses = pfunc $ decode_json json in do mapM_ (printfunc section cp args) statuses return statuses 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 :: Int -> Message -> String shortStatus width m = (printf "%-22s %s\n" ("<" ++ sSender m ++ ">") (head wrappedtext)) ++ concatMap (printf "%-22s %s\n" "") (tail wrappedtext) where wrappedtext = map unwords $ wrapLine (width - 22 - 2) (words (sText m)) shortDM :: Int -> Message -> String shortDM width m = (printf "%-22s %-22s %s\n" ("<" ++ sSender m ++ ">") ("<" ++ sRecipient m ++ ">") (head wrappedtext)) ++ concatMap (printf "%-22s %-22s %s\n" "" "") (tail wrappedtext) where wrappedtext = map unwords $ wrapLine (width - 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 (case lookup "w" args of Just ws -> read ws Nothing -> defaultWidth) m) (Nothing, Just _) -> putStr (longfunc m) Just recipient -> mailto section cp args m recipient 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 (filter (/= '\n') $ 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] ) ++ (case twitterToRFC822 (sDate m) of Just d -> [ "Date: " ++ d ] Nothing -> [] ) ++ ["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 ++ ")" ,"" ,"Tweet URL: http://twitter.com/" ++ sSender m ++ "/status/" ++ sId m ,"Reply URL: http://twitter.com/home?status=@" ++ escapeURIString isUnreserved (sSender m ++ " ") ++ "&in_reply_to_status_id=" ++ sId m ++ "&in_reply_to=" ++ escapeURIString isUnreserved (sSender m) ,"User home: http://twitter.com/" ++ sSender m ] twitterToRFC822 d = formatTime defaultTimeLocale rfc822DateFormat `fmap` time where time :: Maybe ZonedTime time = parseTime defaultTimeLocale "%a %b %e %H:%M:%S %Z %Y" d ---------------------------------------------------------------------- -- Follow/block type commands ---------------------------------------------------------------------- -------------------------------------------------- -- lsfollowing -------------------------------------------------- lsfollowing = simpleCmd "lsfollowing" "List people you are following" lsfollowing_help stdopts (paginated lsfollowing_worker) lsfollowing_worker = genericfb_worker "lsfollowing" "/friends/list.json" 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 = genericfb_worker "lsfollowers" "/followers/list.json" 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" -------------------------------------------------- -- lsblocking -------------------------------------------------- lsblocking = simpleCmd "lsblocking" "List people you are blocking" lsblocking_help stdopts (paginated lsblocking_worker) lsblocking_worker = genericfb_worker "lsblocking" "/blocks/list.json" lsblocking_help = "Usage: twidge lsblocking [options]\n\n\ \List the twitter accounts that your account is blocking.\n" ------------------------------------------------------------ -- Generic follow/block support ------------------------------------------------------------ genericfb_worker cmdname url _ cp (args, user) page = do json <- sendAuthRequest GET cp url params [] debugM cmdname $ "Got doc: " ++ show json let UserList doc nextPage = decode_json json let users = map fromListedUser doc mapM_ (printUser args) users return (users, nextPage) where params = pageParams ++ targetParams pageParams = maybe [] (\c -> [("cursor", c)]) page targetParams = case user of [] -> [] [x] -> [("screen_name", x)] _ -> error $ "Invalid args to " ++ cmdname ++ "; see twidge " ++ cmdname ++ " --help" printUser args (name, userid) = case lookup "l" args of Nothing -> putStrLn name Just _ -> printf "%s\t%s\n" userid name ---------------------------------------------------------------------- -- Generic Utilities ---------------------------------------------------------------------- {- | Calls the workerfunc once if --all wasn't given, to load page 1. Otherwise, calls workerfunc repeatedly to load all pages, one after another, as long as it continues to return data. Used to wrap around worker functions where multiple pages of data can be returned. -} paginated workerfunc cppath cp (args, remainder) | lookup "a" args == Nothing = do workerfunc cppath cp (args, remainder) Nothing return () | otherwise = paginateloop Nothing where paginateloop page = do (r, nextPage) <- workerfunc cppath cp (args, remainder) page if null r then return () else paginateloop nextPage twidge/Commands/Setup.hs0000644000000000000000000001203012156620144012421 0ustar {-# LANGUAGE CPP #-} {- Copyright (C) 2010-2013 John Goerzen 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.Setup(setup) where import Utils import System.Log.Logger import Data.List import Data.ConfigFile import System.IO import Data.Either.Utils import Data.Char import Config import Control.Monad(when) import Network.OAuth.Consumer import Data.Maybe import Network.OAuth.Http.Request import Network.OAuth.Http.HttpClient import OAuth import Data.Binary(encode) import Control.Monad.Trans import qualified Control.Monad.State.Class as M import Download(twidgeCurlClient) i = infoM "setup" d = debugM "setup" -------------------------------------------------- -- setup -------------------------------------------------- setup = simpleCmd "setup" "Interactively configure twidge for first-time use" setup_help [] setup_worker setup_worker cpath cp _ = do hSetBuffering stdout NoBuffering when (has_option cp "DEFAULT" "oauthdata") confirmSetup putStrLn "\nWelcome to twidge. We will now configure twidge for your" putStrLn "use with Twitter (or a similar service). This will be quick and easy!\n" putStrLn "\nPlease wait a moment while I query the server...\n\n" app <- case getApp cp of Nothing -> fail $ "Error: must specify oauthconsumerkey and oauthconsumersecret for non-default host " ++ (serverHost cp) Just x -> return x let reqUrlBase = forceEither $ get cp "DEFAULT" "oauthrequesttoken" let accUrlBase = forceEither $ get cp "DEFAULT" "oauthaccesstoken" let authUrlBase = forceEither $ get cp "DEFAULT" "oauthauthorize" let reqUrl = fromJust . parseURL $ reqUrlBase let accUrl = fromJust . parseURL $ accUrlBase let authUrl = ((authUrlBase ++ "?oauth_token=") ++ ) . findWithDefault ("oauth_token", "") . oauthParams let resp = runOAuthM (fromApplication app) $ do liftIO $ d "Trying first signRq2" reqres1 <- signRq2 HMACSHA1 Nothing reqUrl liftIO $ d $ "First signRq2 result: " ++ (show reqres1) oauthRequest twidgeCurlClient reqres1 twidgeAskAuthorization authUrl liftIO $ d "Trying second signRq2" reqres2 <- signRq2 HMACSHA1 Nothing accUrl liftIO $ d $ "Second signRq2 result: " ++ show reqres2 oauthRequest twidgeCurlClient reqres2 tok <- getToken return tok tok <- resp d $ "Got token: " ++ show tok case tok of AccessToken _ _ -> do let newcp = forceEither $ set cp "DEFAULT" "oauthdata" . esc . show . toList . oauthParams $ tok writeCP cpath newcp putStrLn $ "Successfully authenticated!" putStrLn "Twidge has now been configured for you and is ready to use." _ -> putStrLn "Authentication failed; please try again" where confirmSetup = do putStrLn "\nIt looks like you have already authenticated twidge." putStrLn "If we continue, I may remove your existing" putStrLn "authentication. Would you like to proceed?" putStr "\nYES or NO: " c <- getLine if (map toLower c) == "yes" then return () else permFail "Aborting setup at user request." esc x = concatMap fix x fix '%' = "%%" fix x = [x] twidgeAskAuthorization :: MonadIO m => (Token -> String) -> OAuthMonadT m () twidgeAskAuthorization getUrl = do token <- getToken answer <- liftIO $ do putStrLn "OK, next I need you to authorize Twidge to access your account." putStrLn "Please cut and paste this URL and open it in a web browser:\n" putStrLn (getUrl token) putStrLn "\nClick Allow when prompted. You will be given a numeric" putStrLn "key in your browser window. Copy and paste it here." putStrLn "(NOTE: some non-Twitter services supply no key; just leave this blank" putStrLn "if you don't get one.)\n" putStr "Authorization key: " getLine putToken (injectOAuthVerifier answer token) setup_help = "Usage: twidge setup\n\n" twidge/Commands/FollowBlock.hs0000644000000000000000000000464412156620144013552 0ustar {- Copyright (C) 2006-2009 John Goerzen 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.FollowBlock(follow, unfollow, block, unblock) where import Utils import System.Log.Logger import Download import Network.OAuth.Http.Request i = infoM "followblock" follow = simpleCmd "follow" "Start following someone" follow_help [] follow_worker follow_worker = generic_worker POST "/friendships/create.json" "follow" follow_help = generic_add_help "follow" unfollow = simpleCmd "unfollow" "Stop following someone" unfollow_help [] unfollow_worker unfollow_worker = generic_worker POST "/friendships/destroy.json" "unfollow" unfollow_help = generic_rm_help "follow" block = simpleCmd "block" "Start blocking someone" block_help [] block_worker block_worker = generic_worker POST "/blocks/create.json" "block" block_help = generic_add_help "block" unblock = simpleCmd "unblock" "Stop blocking someone" unblock_help [] unblock_worker unblock_worker = generic_worker POST "/blocks/destroy.json" "unblock" unblock_help = generic_rm_help "block" generic_worker method url cmdname _ cp ([], [user_string]) = do let user = strip_at user_string json <- sendAuthRequest method cp url [] [("screen_name", user)] debugM cmdname $ "Got doc: " ++ show json -- return () where strip_at ('@':u) = u strip_at u = u generic_worker _ _ cmdname _ _ _ = permFail $ "follow: syntax error; see twidge " ++ cmdname ++ " --help" generic_add_help cmd = "Usage: twidge " ++ cmd ++ " username\n\n\ \will add username to your list of people you " ++ cmd ++ ".\n\n" generic_rm_help cmd = "Usage: twidge un" ++ cmd ++ " username\n\n\ \will remove username from the list of people you " ++ cmd ++ ".\n" twidge/Commands/Update.hs0000644000000000000000000001733212156620144012555 0ustar {-# LANGUAGE CPP #-} {- Copyright (C) 2006-2008 John Goerzen 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.Update(update, dmsend) where import Utils import System.Log.Logger import Types import System.Console.GetOpt import System.Console.GetOpt.Utils import Download import Control.Monad(when) import Text.Regex.Posix import Data.ConfigFile import MailParser(message) import Text.ParserCombinators.Parsec import Network.OAuth.Http.Request #ifdef USE_BITLY import Network.Bitly (Account(..),bitlyAccount,jmpAccount,shorten) #endif import qualified Codec.Binary.UTF8.String as UTF8 i = infoM "update" d = debugM "update" update = simpleCmd "update" "Update your status" update_help [Option "r" ["recvmail"] (NoArg ("m", "")) "Receive update as body of email on stdin", Option "i" ["inreplyto"] (ReqArg (stdRequired "i") "MSGID") "Indicate this message is in reply to MSGID" ] update_worker_wrapper update_worker_wrapper x cp args = do d $ "Running update_worker with: " ++ show (x, args) update_worker x cp (newargs args) where newargs (opts, status) = (opts, map UTF8.decodeString status) update_worker x cp ([("m", "")], []) = do d "Reading mail message" c <- getContents case parse message "(stdin)" c of Left x -> permFail $ "Couldn't parse mail: " ++ show x Right (refs, body) -> let irt = case refs =~ "<([^>]+)>$" of "" -> [] m -> case parseMsgId m of Nothing -> [] Just (m, host, section) -> if host == serverHost cp && section `elem` ["lsrecent", "lsarchive", "lsreplies"] then [("in_reply_to_status_id", sId m)] else [] status = body in do poststatus <- procStatus cp "update" status json <- sendAuthRequest POST cp "/statuses/update.json" [] ([("status", poststatus)] ++ irt) debugM "update" $ "Got doc: " ++ show json update_worker x cp ([], []) = do d "No args reading line" l <- getLine update_worker x cp ([], [l]) update_worker x cp ([("i", id )], []) = do d "-i reading line" l <- getLine update_worker x cp ([("i", id)], [l]) update_worker _ cp ([("i", id)], [status]) = do d "-i have line" poststatus <- procStatus cp "update" status json <- sendAuthRequest POST cp "/statuses/update.json" [] [("status", poststatus), ("in_reply_to_status_id", id)] debugM "update" $ "Got doc: " ++ show json update_worker _ cp ([], [status]) = do d "no args have line" poststatus <- procStatus cp "update" status json <- sendAuthRequest POST cp "/statuses/update.json" [] [("status", poststatus)] debugM "update" $ "Got doc: " ++ show json update_worker _ _ _ = permFail "update: syntax error; see twidge update --help" procStatus cp section status = do poststatus <- case get cp section "shortenurls" of Right True -> case get cp section "shortenall" of Right True -> shortenUrls cp status _ | length status > 140 -> shortenUrls cp status _ -> return status _ -> return status when (length poststatus > 140) (permFail $ "Your status update was " ++ show (length poststatus) ++ " characters; max length 140") return poststatus dmsend = simpleCmd "dmsend" "Send direct message" dmsend_help [] dmsend_worker dmsend_worker x cp ([], [r]) = do l <- getLine dmsend_worker x cp ([], [r, l]) dmsend_worker x cp ([], [recipient, status]) = do poststatus <- procStatus cp "dmsend" status json <- sendAuthRequest POST cp "/direct_messages/new.json" [] [("text", poststatus), ("screen_name", recipient)] debugM "dmsend" $ "Got doc: " ++ show json dmsend_worker _ _ _ = permFail "Syntax error; see twidge dmsend --help" shortenUrls _ "" = return "" shortenUrls cp status = do debugM "update" $ "shortenUrls considering: " ++ show status shortURL <- chooseShortener cp if match == "" then return before -- No match means no "after" else do tiny <- shortURL match debugM "update" $ "Got tinyurl: " ++ show tiny rest <- shortenUrls cp after return $ before ++ (if (length tiny < length match) then tiny else match) ++ rest where (before, match, after) = status =~ pat pat = "(http|https|ftp)\\://[a-zA-Z0-9\\-\\.]+(:[a-zA-Z0-9]*)?/?([-a-zA-Z0-9:()\\._\\?\\,\\'/\\\\\\+&%\\$#\\=~])*" #ifdef USE_BITLY chooseShortener cp = do -- look either for [bitly] or [jmp] section in config let (sec, newAccount) = if has_section cp "bitly" then ("bitly", bitlyAccount) else ("jmp", jmpAccount) -- [bitly] or [jmp] section should define both login and apikey let acc = get cp sec "login" >>= \l -> get cp sec "apikey" >>= \k -> return $ newAccount { login=l, apikey=k } return $ case acc of Left _ -> mkTinyURL -- use default Right a -> mkBitlyURL a mkBitlyURL acc url = do r <- shorten acc url case r of Left e -> permFail e -- report bit.ly errors Right shorturl -> return shorturl #else chooseShortener _ = return mkTinyURL #endif mkTinyURL url = simpleDownload . concat $ "http://is.gd/api.php?longurl=" : map escapeHashes url where -- NOTE: This technique works with the is.gd "API" -- but does not work with the tinyurl.com "API" escapeHashes :: Char -> String escapeHashes '#' = "%23" escapeHashes c = [c] update_help = "Usage: twidge update [status]\n\n" ++ "Updates your status to the given status. You will most likely need to\n" ++ "quote this to prevent interference from the shell. For instance:\n\n" ++ " twidge update \"At home, baking.\"\n\n" ++ "You can also omit the status, in which case a single line will be read\n" ++ "from stdin and taken as your update. Example:\n\n" ++ " date | twidge update\n" dmsend_help = "Usage: twidge dmsend recipient [status]\n\n" ++ "Sends a direct message to the given recipient. You will most likely need\n" ++ "to quote this to prevent interference from the shell. For instance:\n\n" ++ " twidge dmsend unixtwidge \"At home, baking.\"\n\n" ++ "You can also omit the status, in which case a single line will be read\n" ++ "from stdin and taken as your update. Example:\n\n" ++ " date | twidge dmsend unixtwidge\n" twidge/twidge.bash_completion0000644000000000000000000000137411652026731013612 0ustar #-*- mode: shell-script;-*- # twidge command line completion. # Copyright 2010 Ernesto Hernández-Novich # Licensed under the GNU General Public License, version 2 : ${have=$(command -v twidge)} test -n "$have" && _twidge() { local cur cur=${COMP_WORDS[COMP_CWORD]} COMPREPLY=() if (($COMP_CWORD == 1)); then COMPREPLY=( $( twidge lscommands | tail --lines=+4 | cut -f1 -d' '| grep "^$cur" ) ) return 0 fi local i=${#COMPREPLY[*]} local colonprefixes=${cur%"${cur##*:}"} while [ $((--i)) -ge 0 ]; do COMPREPLY[$i]=`printf %q "${COMPREPLY[$i]}"` COMPREPLY[$i]=${COMPREPLY[$i]#"$colonprefixes"} done return 0 } test -n "$have" && complete -F _twidge -o default twidge twidge/MailParser.hs0000644000000000000000000000336712156620144011634 0ustar {- Copyright (C) 2006-2008 John Goerzen 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 MailParser where import Text.ParserCombinators.Parsec import Data.String.Utils import Types(sanitize) eol = (string "\r\n") <|> string "\n" line = do l <- many (noneOf "\r\n") eol return l line1 = do l <- many1 (noneOf "\r\n") eol return l header = do c1 <- (refHdr <|> (line1 >> return "")) return c1 refHdr = do try (string "References: ") c <- line c2 <- restOfHdr return (c ++ c2) where restOfHdr = (do oneOf " \t" r <- line n <- restOfHdr return (r ++ n)) <|> return "" headers = many1 header maybeFrom = try (do string "From " many1 (noneOf "\r\n") eol return () ) <|> (return ()) body = do b <- many anyChar eof return b message = do maybeFrom h <- headers eol b <- body return (strip (concat h), strip . sanitize $ b) twidge/Makefile0000644000000000000000000000124111401534175010666 0ustar # arch-tag: Primary makefile # Copyright (c) 2004-2006 John Goerzen # all: setup # GHC build ./setup configure ./setup build doc: lib/dfs.html/index.html lib/dfs.pdf lib/dfs.ps lib/dfs.txt hugsbuild: setup ./setup configure --hugs ./setup build setup: Setup.lhs twidge.cabal ghc -package Cabal Setup.lhs -o setup clean: clean-code clean-doc clean-code: -./setup clean -cd libsrc && ../setup clean -rm -rf dist libsrc/dist *.ho *.hi *.o *.a setup *~ -rm -f `find . -name "*~"` `find . -name "*.o"` -rm -f `find . -name "*.cm*"` clean-doc: -cd doc && scons -c && scons -c html pdf text ps -rm -rf doc/.sconsign* .depend test -rm -f doc/manpage* doc/*.1 twidge/doc/0000755000000000000000000000000012276505371010004 5ustar twidge/doc/twidge-manpage.sgml0000644000000000000000000011236412156620144013561 0ustar twidgeReference For
jgoerzen@complete.org
JohnGoerzen
twidge 1 John Goerzen twidge Microblogging client for Twitter, Identica twidge -d -c FILE command command_args twidge --help 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 . 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. Feature List Convenient, easy to learn, and fast command-line interface (it's simple to do simple things, and advanced things are possible) This extensive manual, and numerous examples on the website Compatible with any microblogging service that implements the Twitter API. Tested with Twitter and Identica (identi.ca). Should be compatible with any other system. Full support for reading the activity of your friends, replies to you, and your own activity. Optional capability to remember what you have seen already and suppress those updates in future runs. Optional automatic shortening of long URLs via is.gd Optional integration with your email system -- send and receive updates via email. Specifically designed to be friendly to use in shell scripts. Shell scripting makes it easy to do many things, such as scheduling future updates (with at), ignoring certain updates (with grep), etc. Easy use of multiple accounts by having multiple configuration profiles. Mechanism lends itself to shell aliases and tools. Small, minimalist footprint Output formats are easily parsed. Input formats are easily generated. Configuration file format is liberal and easy to generate. Robust error detection and recovery throughout. Quick Start 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 INSTALL file in the source distribution. To get started, simply run twidge setup at your shell prompt. &twidge; will lead you through the first-time configuration -- which is very quick and completely self-explanatory! Now, let's start exploring. twidge lsrecent -su 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 lsrecent, you could substitue lsreplies to replies to you. You can also run twidge lsrecent --help, 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. You can subscribe to updates from friends by running twidge follow nick. To subscribe to updates for &twidge; itself, you'd run twidge follow unixtwidge. If you've had enough of updates from someone, just use the twidge unfollow command. Now, how about posting your own updates? Just type twidge update. 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. That's the quick tour. For many more examples, refer to the website. Options (command-line) Options &twidge; always is invoked with the name of a specific operation, such as or . In &twidge;, these operations are called commands. 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. You may obtain a list of all commands with twidge lscommands. Help is available for any individual command with twidge command --help. Global help is available with twidge --help. Global Options These options may be specified before any command. -c FILE --config=FILE By default, &twidge; uses ~/.twidgerc 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 twidge setup command, or the -s option to one of the ls commands. -d--debug 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. Commands Commands in Twidge &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 given in lowercase. All commands support the option . Running twidge command --help will display information about the command and its options. Since all commands support this, it won't be explicitly listed for each command below. Commands to Display Updates twidge ls* -a -l -s -u Several commands can display updates from yourself or others. They all share a common syntax and common set of options. The commands are lsdm, lsdmarchive, lsrecent, lsreplies, and lsrtreplies. Here are the common options: -a --all 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. 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. -e command --exec=command 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: The update ID for the given update. The username that created the update A suggested Message-ID for representing the update in email. Contains the enclosing angle brackets. The update text itself. Likely contains spaces and other shell metacharacters. -l --long 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. 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. -m address --mailto=address 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. 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. 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. -s --saveid Saves the ID of the most recent fetched message for future use with -u. Requires write access to your configuration file. -u --unseen 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. 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. lsdm Lists direct messages sent to you. Note: identi.ca does not support direct messages, and this will cause an error with that service. lsdmarchive Lists direct messages you have sent. Note: identi.ca does not support direct messages, and this command will cause an error with that service. lsrecent Lists recent posts made by you or the people you follow. lsreplies Lists recent replies made by anyone on the microblogging site to you. lsrtreplies List retweets of your statuses made by others. Note: identi.ca doesn't support new-style retweets and will return an error on this command. Commands to Display Other Information These commands honor --all and --long like the other commands, but do not honor --saveid or --unseen, as these options make no sense. lsfollowers twidge lsfollowers options username 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. lsfollowing twidge lsfollowing options username Shows a list of the people you follow. Arguments and actions are the same as with lsfollowers. Action Commands These commands perform an action on the server. dmsend twidge dmsend recipient status 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. 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. By default, Twidge will attempt to shorten URLs in your updates via an URL shortening service, but only if your update's length exceeds 140 characters. This means long URLs shorter than 140 characters WILL NOT be shortened. If you want all your URLs to be shortened all the time regardless of their length, then set shortenall = yes in the [DEFAULT] or [dmsend] section of your configuration file. You can disable URL shortening altogether by setting shortenurls = no in the [DEFAULT] or [dmsend] section of your configuration file. follow twidge follow username 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. setup twidge setup Enters the interactive first-time setup tool. unfollow twidge unfollow username 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. update twidge update -i MSGID | --inreplyto MSGID status twidge update -r 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. 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. By default, Twidge will attempt to shorten URLs in your updates via an URL shortening service, but only if your update's length exceeds 140 characters. This means long URLs shorter than 140 characters WILL NOT be shortened. If you want all your URLs to be shortened all the time regardless of their length, then set shortenall = yes in the [DEFAULT] or [dmsend] section of your configuration file. You can disable URL shortening altogether by setting shortenurls = no in the [DEFAULT] or [dmsend] section of your configuration file. 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 twidge lsrecent --mailto 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. 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. When -i is given, the internal Twitter ID of a message is expected to be passed. This sets the "in reply to" flag on Twitter appropriately. Other Command Commandslscommands lscommands twidge lscommands This command will display a list of all available &twidge; commands along with a brief description of each. twidge Configuration File &twidge; has a configuration file in which you can set various options. This file normally lives under ~/.twidgerc. 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. 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 urlbase, are assumed to be in DEFAULT. Let's start by looking at an example file, and then proceed to examine all the options that are available. 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 section. If it still doesn't find an answer, it consults its built-in defaults. General Options These are specified in the section. serverbase The base URL to access the API of the microblogging site. This should contain the server name but not the API path. The default is https://api.twitter.com. For Identica, you would use http://identi.ca/api (note that some users have trouble if attempting to use SSL with identica).. urlbase The URL to access the API of the microblogging site. The default, %(serverbase)s/1 is for Twitter. To use Identica, you would specify %(serverbase)s. Do not put a trailing slash on this option. oauthrequesttoken The URL to access the oAuth request token interface. The default, %(serverbase)s/oauth/request_token, will work with most environments. oauthaccesstoken The oAuth access token URL. Default is %(serverbase)s/oauth/access_token. oauthauthorize The oAuth authorize URL. Default is %(serverbase)s/oauth/authorize. oauthconsumerkey The oAuth consumer key. Twidge is registered with Twitter and identi.ca and will supply a reasonable default for those two based on the content of urlbase. oauthconsumersecret The oAuth consumer secret. A default is provided as with oauthconsumerkey. oauthdata Automatically written by twidge setup. Do not alter. Per-Command Options These options may be specified in or in a per-option section. If placed in , they will apply to all relevant options unless overridden. lastid Stores the last ID seen for commands that support -s or -u. mailfrom 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. Should contain a bare email address only -- no brackets, parens, quotes, or comments. When given, Twidge uses the nickname and this address for the From line. When not given, the nickname is prepended to the Subject line. savelast For one of the "ls" class of commands, implies -s on every invocation, rather than require it to be manually given. This option need only be present; the value you give it doesn't mater. sendmail 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. shortenurls You may specify shortenurls in the [update] section. It defaults to yes. If set to no, will cause &twidge; to omit its attempt to shorten URLs in your updates. If set to yes, will cause &twidge; to shorten URLs in your updates, only if the latter's length exceeds 140 characters. See shortenall shortenall You may specify shortenall in the [update] section. It defaults to no. If set to yes, will cause &twidge; to shorten all URLs in your updates, all the time. It only makes sense if shortenurls is set to yes. URL Shortening Options &twidge; uses is.gd as its default URL shortening service. To enable the bit.ly or j.ump URL shorteners, you must add a [bitly] or [jmp] section to the configuration file. This should contain two entries: login and apikey as found in . For example: [jmp] login: bitlyapidemo apikey: R_0da49e0a9118ff35f52f629d2d71bf07 Aliases You can add an [alias] section to the config file which will effectively create new commands. For example: [alias] recent: lsrecent -u replies: lsreplies -u Tips & Hints Here are a few tips and hints to make &twidge; more pleasant for you. Going Through a Proxy 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. Environment &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 curl(1) for more details. Conforming To The Extensible Markup Language (XML) standard (W3C) Copyright Copyright &twidge;, all code, documentation, files, and build scripts are Copyright © 2006-2008 John Goerzen. All code, documentation, sripts, and files 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. Author &twidge;, its modules, documentation, executables, and all included files, except where noted, was written by John Goerzen jgoerzen@complete.org and copyright is held as stated in the COPYRIGHT section. See Also curl(1) The &twidge; homepage at .
twidge/doc/man.twidge.sgml0000644000000000000000000000052711401534175012722 0ustar twidge"> ]> twidge Manual &man.twidge; twidge/doc/sgml-common/0000755000000000000000000000000011401534175012225 5ustar twidge/doc/sgml-common/SConstruct0000644000000000000000000001646511401534175014273 0ustar # 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']+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) twidge/doc/sgml-common/Makefile.common0000644000000000000000000001536011401534175015161 0ustar # -*- Mode: makefile; -*- # arch-tag: Primary sgml-common top-level Makefile # Common Makefile for SGML documents # # Copyright (C) 2002, 2003 John Goerzen # # # 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) twidge/doc/sgml-common/COPYRIGHT0000644000000000000000000000322411401534175013521 0ustar Copyright for all code except ps2epsi ------------------------------------- # Copyright (C) 2002, 2003 John Goerzen # # # 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 twidge/doc/sgml-common/ps2epsi0000644000000000000000000000326411401534175013542 0ustar #!/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 twidge/doc/sgml-common/COPYING0000644000000000000000000004315511401534175013270 0ustar 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. Copyright (C) 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. , 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 twidge/doc/sgml-common/ChangeLog0000644000000000000000000001155411401534175014005 0ustar # 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 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 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 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 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 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 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 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 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 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 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 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 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 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 patch-7 Summary: Checkpointing Revision: sgml-common--head--1.0--patch-7 modified files: SConstruct 2004-02-02 19:18:40 GMT John Goerzen 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 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 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 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 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 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 base-0 Summary: initial import Revision: sgml-common--head--1.0--base-0 (automatically generated log message) new files: COPYING COPYRIGHT Makefile.common ps2epsi twidge/doc/SConstruct0000644000000000000000000000220211401534175012023 0ustar # Copyright (C) 2004-2006 John Goerzen # # # 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) twidge/doc/twidge.sgml0000644000000000000000000000055011401534175012144 0ustar twidge"> ]> twidge Manual &man.twidge; twidge/doc/local.dsl0000644000000000000000000000213011401534175011567 0ustar ]> (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... )) twidge/doc/printlocal.dsl0000644000000000000000000000120611401534175012647 0ustar ]> (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) twidge/Utils.hs0000644000000000000000000001247111401534175010671 0ustar {- Copyright (C) 2006-2008 John Goerzen 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 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>" ---------------------------------------------------------------------- -- Start of code from Cabal 1.4.0.2 -- | Wraps text to the default line width. Existing newlines are preserved. wrapText :: String -> String wrapText = unlines . concatMap (map unwords . wrapLine 79 . words) . lines -- | Wraps a list of words to a list of lines of words of a particular width. wrapLine :: Int -> [String] -> [[String]] wrapLine width = wrap 0 [] where wrap :: Int -> [String] -> [String] -> [[String]] wrap 0 [] (w:ws) | length w + 1 > width = wrap (length w) [w] ws wrap col line (w:ws) | col + length w + 1 > width = reverse line : wrap 0 [] (w:ws) wrap col line (w:ws) = let col' = col + length w + 1 in wrap col' (w:line) ws wrap _ [] [] = [] wrap _ line [] = [reverse line] -- End of code from Cabal 1.4.0.2 ---------------------------------------------------------------------- twidge/Download.hs0000644000000000000000000001006412156620144011334 0ustar {- hpodder component Copyright (C) 2006-2013 John Goerzen 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-2013 John Goerzen License : GNU GPL, version 2 or above Maintainer : John Goerzen Stability : provisional Portability: portable Written by John Goerzen, jgoerzen\@complete.org -} module Download(sendAuthRequest, simpleDownload, twidgeCurlClient) where import Control.Monad(unless) import System.Log.Logger import Data.ConfigFile import Data.List import Network.URI import Data.Either.Utils(forceEither) import Data.Maybe import Network.OAuth.Http.Request import Network.OAuth.Http.Response import Network.OAuth.Http.CurlHttpClient import Network.OAuth.Http.HttpClient import Network.Curl import Network.OAuth.Consumer import OAuth import Data.ByteString.Lazy(ByteString) import Data.ByteString.Lazy.UTF8(toString) d = debugM "download" i = infoM "download" twidgeCurlClient :: CurlClient twidgeCurlClient = OptionsCurlClient [CurlLowSpeedTime 60 ,CurlLowSpeed 1 ,CurlUserAgent "twidge v1.1.0; Haskell. GHC" ,CurlFollowLocation True -- follow redirects ,CurlFailOnError True -- fail on server errors ] {- | Download a webpage without using oauth. -} simpleDownload :: String -> IO String simpleDownload url = do r <- resp d $ "simpleDownload response from URL " ++ show url ++ ": " ++ show r return . toString . rspPayload $ r where resp = (runClient_ twidgeCurlClient) (fromJust $ parseURL url) needsUpgrade :: String needsUpgrade = unlines $ ["Your configuration needs to be updated to work with changes at Twitter." ,"Please edit your configuration file and fix the urlbase option. In most" ,"cases, you can set it like this:" ,"" ,"urlbase: %(serverbase)s/1.1"] sendAuthRequest :: Method -> ConfigParser -> String -> [(String, String)] -> [(String, String)] -> IO ByteString sendAuthRequest mth cp url getopts postoptlist = do app <- case getApp cp of Nothing -> fail $ "Error: auth not set up for this host" Just x -> return x oauthdata <- case get cp "DEFAULT" "oauthdata" of Left x -> fail $ "Need to (re-)run twidge setup to configure auth: " ++ show x Right y -> return y unless (urlbase /= "https://api.twitter.com/1") $ fail $ needsUpgrade let parsedUrl = fromJust . parseURL $ urlbase ++ url ++ optstr -- add to the request the GET/POST headers let request = parsedUrl {qString = fromList (toList (qString parsedUrl) ++ postoptlist) ,method = mth } let token = AccessToken app (fromList (read oauthdata)) let resp = runOAuthM token $ do r <- signRq2 HMACSHA1 (Just $ Realm "realm") request serviceRequest twidgeCurlClient r r <- resp d $ "response: " ++ show r return . rspPayload $ r where urlbase = forceEither $ get cp "DEFAULT" "urlbase" optstr = case getopts of [] -> "" _ -> "?" ++ (concat . intersperse "&" . map conv $ getopts) conv (k, v) = k ++ "=" ++ escapeURIString isUnreserved v twidge/Config.hs0000644000000000000000000000632712156620144011001 0ustar {- hpodder component Copyright (C) 2006-2010 John Goerzen 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-2010 John Goerzen License : GNU GPL, version 2 or above Maintainer : John Goerzen 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, setFileCreationMask) import System.Log.Logger getDefaultCP = do return $ forceEither $ do cp <- set startingcp "DEFAULT" "serverbase" "https://api.twitter.com" cp <- set cp "DEFAULT" "urlbase" "%(serverbase)s/1.1" cp <- set cp "DEFAULT" "oauthrequesttoken" "%(serverbase)s/oauth/request_token" cp <- set cp "DEFAULT" "oauthaccesstoken" "%(serverbase)s/oauth/access_token" cp <- set cp "DEFAULT" "oauthauthorize" "%(serverbase)s/oauth/authorize" cp <- set cp "DEFAULT" "sendmail" "/usr/sbin/sendmail" cp <- set cp "DEFAULT" "shortenurls" "yes" cp <- set cp "DEFAULT" "shortenall" "no" return cp startingcp = emptyCP {accessfunc = interpolatingAccess 10} getCPName = do appdir <- getUserDocumentsDirectory return $ appdir ++ "/.twidgerc" loadCP useDefaultIfMissing cpgiven = do cpname <- case cpgiven of Nothing -> getCPName Just x -> return x defaultcp <- getDefaultCP dfe <- doesFileExist cpname debugM "Config" $ "CP " ++ cpname ++ " exists? " ++ show dfe if dfe then do cp <- readfile defaultcp cpname return $ forceEither cp else if useDefaultIfMissing then return defaultcp 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" setFileCreationMask 0o0077 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 twidge/INSTALL0000644000000000000000000000023411401534175010260 0ustar 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